aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx25840
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-09-26 22:32:54 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:40:17 -0500
commitc7dd1ecdc0112b9700ed6ad20a6e4e07d125044b (patch)
treecdf1bcf18b3e0e48753e0c3212adff139af908da /drivers/media/video/cx25840
parent29f8a0a50ac32ac4bc1937dcfdf8de6c406a5f10 (diff)
V4L/DVB (13087): cx25840: Improve detection of CX2388[578] A/V cores
Add improved logic to detect the exact CX2388[578] A/V core that is being probed. Also cleaned up detection and logging for CX2310[12], CX2583[67], and CX2584[0123] cores and chips. Also added code to identify a CX2388[578] A/V decoder core that is not responding properly. Typical symptoms include registers 0x00-0xff responding properly but all other registers returning the same value (0x13 and 0x5 have been observed). This state will cause proper detection of '885 vs. '887 vs. '888 to fail and the chip won't respond to get configured properly anyway. I have no method of reseting the core to a working state at this time; but I didn't try too hard to work one out either. The problem likely only occurs in development. I suspect configuring the SYS PLL VCO to oscillate too slowly (286.3 MHz?) before post divide may be the root cause, when encountered. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c97
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 1aeaf18a9bea..e83656729991 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 = {
1521 1521
1522/* ----------------------------------------------------------------------- */ 1522/* ----------------------------------------------------------------------- */
1523 1523
1524static u32 get_cx2388x_ident(struct i2c_client *client)
1525{
1526 u32 ret;
1527
1528 /* Come out of digital power down */
1529 cx25840_write(client, 0x000, 0);
1530
1531 if (cx25840_read4(client, 0x204) & 0xffff) {
1532 /* IR Tx Clk Divider register exists; chip must be a CX23885 */
1533 ret = V4L2_IDENT_CX23885_AV;
1534 } else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
1535 /* DIF PLL Freq Word reg exists; chip must be a CX23888 */
1536 ret = V4L2_IDENT_CX23888_AV;
1537 } else {
1538 /* A CX23887 A/V core has neither IR nor DIF */
1539 ret = V4L2_IDENT_CX23887_AV;
1540 }
1541
1542 /* Back into digital power down */
1543 cx25840_write(client, 0x000, 2);
1544 return ret;
1545}
1546
1524static int cx25840_probe(struct i2c_client *client, 1547static int cx25840_probe(struct i2c_client *client,
1525 const struct i2c_device_id *did) 1548 const struct i2c_device_id *did)
1526{ 1549{
1527 struct cx25840_state *state; 1550 struct cx25840_state *state;
1528 struct v4l2_subdev *sd; 1551 struct v4l2_subdev *sd;
1529 u32 id; 1552 u32 id = V4L2_IDENT_NONE;
1530 u16 device_id; 1553 u16 device_id;
1531 1554
1532 /* Check if the adapter supports the needed features */ 1555 /* Check if the adapter supports the needed features */
@@ -1543,17 +1566,22 @@ static int cx25840_probe(struct i2c_client *client,
1543 * 0x83 for the cx2583x and 0x84 for the cx2584x */ 1566 * 0x83 for the cx2583x and 0x84 for the cx2584x */
1544 if ((device_id & 0xff00) == 0x8300) { 1567 if ((device_id & 0xff00) == 0x8300) {
1545 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; 1568 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
1546 } 1569 } else if ((device_id & 0xff00) == 0x8400) {
1547 else if ((device_id & 0xff00) == 0x8400) {
1548 id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); 1570 id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
1549 } else if (device_id == 0x0000) { 1571 } else if (device_id == 0x0000) {
1550 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; 1572 id = get_cx2388x_ident(client);
1551 } else if (device_id == 0x1313) {
1552 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
1553 } else if ((device_id & 0xfff0) == 0x5A30) { 1573 } else if ((device_id & 0xfff0) == 0x5A30) {
1554 id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); 1574 /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
1555 } 1575 id = V4L2_IDENT_CX2310X_AV;
1556 else { 1576 } else if ((device_id & 0xff) == (device_id >> 8)) {
1577 v4l_err(client,
1578 "likely a confused/unresponsive cx2388[578] A/V decoder"
1579 " found @ 0x%x (%s)\n",
1580 client->addr << 1, client->adapter->name);
1581 v4l_err(client, "A method to reset it from the cx25840 driver"
1582 " software is not known at this time\n");
1583 return -ENODEV;
1584 } else {
1557 v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); 1585 v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
1558 return -ENODEV; 1586 return -ENODEV;
1559 } 1587 }
@@ -1564,17 +1592,50 @@ static int cx25840_probe(struct i2c_client *client,
1564 1592
1565 sd = &state->sd; 1593 sd = &state->sd;
1566 v4l2_i2c_subdev_init(sd, client, &cx25840_ops); 1594 v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
1567 /* Note: revision '(device_id & 0x0f) == 2' was never built. The 1595 switch (id) {
1568 marking skips from 0x1 == 22 to 0x3 == 23. */ 1596 case V4L2_IDENT_CX23885_AV:
1569 v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", 1597 state->is_cx23885 = 1;
1570 (device_id & 0xfff0) >> 4, 1598 v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
1571 (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f), 1599 client->addr << 1, client->adapter->name);
1572 client->addr << 1, client->adapter->name); 1600 break;
1601 case V4L2_IDENT_CX23887_AV:
1602 state->is_cx23885 = 1;
1603 v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n",
1604 client->addr << 1, client->adapter->name);
1605 break;
1606 case V4L2_IDENT_CX23888_AV:
1607 state->is_cx23885 = 1;
1608 v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n",
1609 client->addr << 1, client->adapter->name);
1610 break;
1611 case V4L2_IDENT_CX2310X_AV:
1612 state->is_cx231xx = 1;
1613 v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n",
1614 device_id, client->addr << 1, client->adapter->name);
1615 break;
1616 case V4L2_IDENT_CX25840:
1617 case V4L2_IDENT_CX25841:
1618 case V4L2_IDENT_CX25842:
1619 case V4L2_IDENT_CX25843:
1620 /* Note: revision '(device_id & 0x0f) == 2' was never built. The
1621 marking skips from 0x1 == 22 to 0x3 == 23. */
1622 v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
1623 (device_id & 0xfff0) >> 4,
1624 (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1
1625 : (device_id & 0x0f),
1626 client->addr << 1, client->adapter->name);
1627 break;
1628 case V4L2_IDENT_CX25836:
1629 case V4L2_IDENT_CX25837:
1630 state->is_cx25836 = 1;
1631 default:
1632 v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n",
1633 (device_id & 0xfff0) >> 4, device_id & 0x0f,
1634 client->addr << 1, client->adapter->name);
1635 break;
1636 }
1573 1637
1574 state->c = client; 1638 state->c = client;
1575 state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
1576 state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
1577 state->is_cx231xx = (device_id == 0x5a3e);
1578 state->vid_input = CX25840_COMPOSITE7; 1639 state->vid_input = CX25840_COMPOSITE7;
1579 state->aud_input = CX25840_AUDIO8; 1640 state->aud_input = CX25840_AUDIO8;
1580 state->audclk_freq = 48000; 1641 state->audclk_freq = 48000;