diff options
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 97 |
1 files changed, 79 insertions, 18 deletions
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 1aeaf18a9be..e8365672999 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1521,12 +1521,35 @@ static const struct v4l2_subdev_ops cx25840_ops = { /* ----------------------------------------------------------------------- */ +static u32 get_cx2388x_ident(struct i2c_client *client) +{ + u32 ret; + + /* Come out of digital power down */ + cx25840_write(client, 0x000, 0); + + if (cx25840_read4(client, 0x204) & 0xffff) { + /* IR Tx Clk Divider register exists; chip must be a CX23885 */ + ret = V4L2_IDENT_CX23885_AV; + } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { + /* DIF PLL Freq Word reg exists; chip must be a CX23888 */ + ret = V4L2_IDENT_CX23888_AV; + } else { + /* A CX23887 A/V core has neither IR nor DIF */ + ret = V4L2_IDENT_CX23887_AV; + } + + /* Back into digital power down */ + cx25840_write(client, 0x000, 2); + return ret; +} + static int cx25840_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct cx25840_state *state; struct v4l2_subdev *sd; - u32 id; + u32 id = V4L2_IDENT_NONE; u16 device_id; /* Check if the adapter supports the needed features */ @@ -1543,17 +1566,22 @@ static int cx25840_probe(struct i2c_client *client, * 0x83 for the cx2583x and 0x84 for the cx2584x */ if ((device_id & 0xff00) == 0x8300) { id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; - } - else if ((device_id & 0xff00) == 0x8400) { + } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); } else if (device_id == 0x0000) { - id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; - } else if (device_id == 0x1313) { - id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; + id = get_cx2388x_ident(client); } else if ((device_id & 0xfff0) == 0x5A30) { - id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); - } - else { + /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */ + id = V4L2_IDENT_CX2310X_AV; + } else if ((device_id & 0xff) == (device_id >> 8)) { + v4l_err(client, + "likely a confused/unresponsive cx2388[578] A/V decoder" + " found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + v4l_err(client, "A method to reset it from the cx25840 driver" + " software is not known at this time\n"); + return -ENODEV; + } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); return -ENODEV; } @@ -1564,17 +1592,50 @@ static int cx25840_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &cx25840_ops); - /* Note: revision '(device_id & 0x0f) == 2' was never built. The - marking skips from 0x1 == 22 to 0x3 == 23. */ - v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", - (device_id & 0xfff0) >> 4, - (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f), - client->addr << 1, client->adapter->name); + switch (id) { + case V4L2_IDENT_CX23885_AV: + state->is_cx23885 = 1; + v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX23887_AV: + state->is_cx23885 = 1; + v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX23888_AV: + state->is_cx23885 = 1; + v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX2310X_AV: + state->is_cx231xx = 1; + v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n", + device_id, client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX25840: + case V4L2_IDENT_CX25841: + case V4L2_IDENT_CX25842: + case V4L2_IDENT_CX25843: + /* Note: revision '(device_id & 0x0f) == 2' was never built. The + marking skips from 0x1 == 22 to 0x3 == 23. */ + v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", + (device_id & 0xfff0) >> 4, + (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 + : (device_id & 0x0f), + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX25836: + case V4L2_IDENT_CX25837: + state->is_cx25836 = 1; + default: + v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n", + (device_id & 0xfff0) >> 4, device_id & 0x0f, + client->addr << 1, client->adapter->name); + break; + } state->c = client; - state->is_cx25836 = ((device_id & 0xff00) == 0x8300); - state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); - state->is_cx231xx = (device_id == 0x5a3e); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; |