aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;