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 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 | ||
1524 | static 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 | |||
1524 | static int cx25840_probe(struct i2c_client *client, | 1547 | static 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; |