aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c/adv7604.c
diff options
context:
space:
mode:
authorMats Randgaard <matrandg@cisco.com>2013-12-10 07:55:18 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-01-07 03:04:59 -0500
commit3e86aa856d0b1f9d24c2dd83f4e31f93795f34c6 (patch)
treeb604c134a24c405e80dd26307a2c78db18e0a469 /drivers/media/i2c/adv7604.c
parentd261e8428b9fed1d42827677688c457e7197e5d1 (diff)
[media] adv7604: set CEC address (SPA) in EDID
Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/i2c/adv7604.c')
-rw-r--r--drivers/media/i2c/adv7604.c83
1 files changed, 70 insertions, 13 deletions
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index d1de747f4542..d8061c5c30dd 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -72,6 +72,7 @@ struct adv7604_state {
72 u32 present; 72 u32 present;
73 unsigned blocks; 73 unsigned blocks;
74 } edid; 74 } edid;
75 u16 spa_port_a;
75 struct v4l2_fract aspect_ratio; 76 struct v4l2_fract aspect_ratio;
76 u32 rgb_quantization_range; 77 u32 rgb_quantization_range;
77 struct workqueue_struct *work_queues; 78 struct workqueue_struct *work_queues;
@@ -531,9 +532,6 @@ static inline int edid_write_block(struct v4l2_subdev *sd,
531 532
532 v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); 533 v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len);
533 534
534 /* Disables I2C access to internal EDID ram from DDC port */
535 rep_write_and_or(sd, 0x77, 0xf0, 0x0);
536
537 for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) 535 for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
538 err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, 536 err = adv_smbus_write_i2c_block_data(state->i2c_edid, i,
539 I2C_SMBUS_BLOCK_MAX, val + i); 537 I2C_SMBUS_BLOCK_MAX, val + i);
@@ -1623,9 +1621,39 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
1623 return 0; 1621 return 0;
1624} 1622}
1625 1623
1624static int get_edid_spa_location(struct v4l2_subdev *sd, const u8 *edid)
1625{
1626 u8 d;
1627
1628 if ((edid[0x7e] != 1) ||
1629 (edid[0x80] != 0x02) ||
1630 (edid[0x81] != 0x03)) {
1631 return -1;
1632 }
1633
1634 /* search Vendor Specific Data Block (tag 3) */
1635 d = edid[0x82] & 0x7f;
1636 if (d > 4) {
1637 int i = 0x84;
1638 int end = 0x80 + d;
1639
1640 do {
1641 u8 tag = edid[i] >> 5;
1642 u8 len = edid[i] & 0x1f;
1643
1644 if ((tag == 3) && (len >= 5))
1645 return i + 4;
1646 i += len + 1;
1647 } while (i < end);
1648 }
1649 return -1;
1650}
1651
1626static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) 1652static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
1627{ 1653{
1628 struct adv7604_state *state = to_state(sd); 1654 struct adv7604_state *state = to_state(sd);
1655 int spa_loc = get_edid_spa_location(sd, edid->edid);
1656 int tmp = 0;
1629 int err; 1657 int err;
1630 1658
1631 if (edid->pad > ADV7604_EDID_PORT_D) 1659 if (edid->pad > ADV7604_EDID_PORT_D)
@@ -1633,16 +1661,20 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
1633 if (edid->start_block != 0) 1661 if (edid->start_block != 0)
1634 return -EINVAL; 1662 return -EINVAL;
1635 if (edid->blocks == 0) { 1663 if (edid->blocks == 0) {
1636 /* Pull down the hotplug pin */ 1664 /* Disable hotplug and I2C access to EDID RAM from DDC port */
1637 state->edid.present &= ~(1 << edid->pad); 1665 state->edid.present &= ~(1 << edid->pad);
1638 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); 1666 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
1639 /* Disables I2C access to internal EDID ram from DDC port */ 1667 rep_write_and_or(sd, 0x77, 0xf0, state->edid.present);
1640 rep_write_and_or(sd, 0x77, 0xf0, 0x0); 1668
1641 state->edid.blocks = 0;
1642 /* Fall back to a 16:9 aspect ratio */ 1669 /* Fall back to a 16:9 aspect ratio */
1643 state->aspect_ratio.numerator = 16; 1670 state->aspect_ratio.numerator = 16;
1644 state->aspect_ratio.denominator = 9; 1671 state->aspect_ratio.denominator = 9;
1645 v4l2_dbg(2, debug, sd, "%s: clear edid\n", __func__); 1672
1673 if (!state->edid.present)
1674 state->edid.blocks = 0;
1675
1676 v4l2_dbg(2, debug, sd, "%s: clear EDID pad %d, edid.present = 0x%x\n",
1677 __func__, edid->pad, state->edid.present);
1646 return 0; 1678 return 0;
1647 } 1679 }
1648 if (edid->blocks > 2) { 1680 if (edid->blocks > 2) {
@@ -1652,19 +1684,45 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
1652 if (!edid->edid) 1684 if (!edid->edid)
1653 return -EINVAL; 1685 return -EINVAL;
1654 1686
1687 /* Disable hotplug and I2C access to EDID RAM from DDC port */
1655 cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); 1688 cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
1656 state->edid.present &= ~(1 << edid->pad); 1689 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp);
1657 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); 1690 rep_write_and_or(sd, 0x77, 0xf0, 0x00);
1691
1692 v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n",
1693 __func__, edid->pad, state->edid.present);
1694 switch (edid->pad) {
1695 case ADV7604_EDID_PORT_A:
1696 state->spa_port_a = edid->edid[spa_loc];
1697 break;
1698 case ADV7604_EDID_PORT_B:
1699 rep_write(sd, 0x70, (spa_loc < 0) ? 0 : edid->edid[spa_loc]);
1700 rep_write(sd, 0x71, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]);
1701 break;
1702 case ADV7604_EDID_PORT_C:
1703 rep_write(sd, 0x72, (spa_loc < 0) ? 0 : edid->edid[spa_loc]);
1704 rep_write(sd, 0x73, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]);
1705 break;
1706 case ADV7604_EDID_PORT_D:
1707 rep_write(sd, 0x74, (spa_loc < 0) ? 0 : edid->edid[spa_loc]);
1708 rep_write(sd, 0x75, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]);
1709 break;
1710 }
1711 rep_write(sd, 0x76, (spa_loc < 0) ? 0x00 : spa_loc);
1712 rep_write_and_or(sd, 0x77, 0xbf, (spa_loc < 0) ? 0x00 : (spa_loc >> 2) & 0x40);
1713
1714 if (spa_loc > 0)
1715 edid->edid[spa_loc] = state->spa_port_a;
1658 1716
1659 memcpy(state->edid.edid, edid->edid, 128 * edid->blocks); 1717 memcpy(state->edid.edid, edid->edid, 128 * edid->blocks);
1660 state->edid.blocks = edid->blocks; 1718 state->edid.blocks = edid->blocks;
1661 state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15], 1719 state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15],
1662 edid->edid[0x16]); 1720 edid->edid[0x16]);
1663 state->edid.present |= edid->pad; 1721 state->edid.present |= 1 << edid->pad;
1664 1722
1665 err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid); 1723 err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid);
1666 if (err < 0) { 1724 if (err < 0) {
1667 v4l2_err(sd, "error %d writing edid\n", err); 1725 v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad);
1668 return err; 1726 return err;
1669 } 1727 }
1670 1728
@@ -1984,7 +2042,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
1984 ADI recommended setting [REF_01, c. 2.3.3] */ 2042 ADI recommended setting [REF_01, c. 2.3.3] */
1985 cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution 2043 cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution
1986 for digital formats */ 2044 for digital formats */
1987 rep_write(sd, 0x76, 0xc0); /* SPA location for port B, C and D */
1988 2045
1989 /* TODO from platform data */ 2046 /* TODO from platform data */
1990 afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ 2047 afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */