diff options
author | Mats Randgaard <matrandg@cisco.com> | 2013-12-10 07:55:18 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-01-07 03:04:59 -0500 |
commit | 3e86aa856d0b1f9d24c2dd83f4e31f93795f34c6 (patch) | |
tree | b604c134a24c405e80dd26307a2c78db18e0a469 /drivers/media/i2c/adv7604.c | |
parent | d261e8428b9fed1d42827677688c457e7197e5d1 (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.c | 83 |
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 | ||
1624 | static 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 | |||
1626 | static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) | 1652 | static 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 */ |