aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMats Randgaard <matrandg@cisco.com>2013-12-10 07:57:09 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-01-07 03:06:14 -0500
commitdd08beb905cc170c596306661ddbe311765c771b (patch)
tree650a8f68831a901774a1babeb165528efc67b09a
parent3e86aa856d0b1f9d24c2dd83f4e31f93795f34c6 (diff)
[media] adv7604: improve EDID handling
- split edid_write_block() - do not use edid->edid before the validity check - Return -EINVAL if edid->pad is invalid - Save both registers for SPA port A - Set SPA location to default value if it is not found 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>
-rw-r--r--drivers/media/i2c/adv7604.c94
1 files changed, 50 insertions, 44 deletions
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index d8061c5c30dd..501f40f5024f 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -72,7 +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 u16 spa_port_a[2];
76 struct v4l2_fract aspect_ratio; 76 struct v4l2_fract aspect_ratio;
77 u32 rgb_quantization_range; 77 u32 rgb_quantization_range;
78 struct workqueue_struct *work_queues; 78 struct workqueue_struct *work_queues;
@@ -510,22 +510,9 @@ static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val)
510 return 0; 510 return 0;
511} 511}
512 512
513static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
514{
515 struct delayed_work *dwork = to_delayed_work(work);
516 struct adv7604_state *state = container_of(dwork, struct adv7604_state,
517 delayed_work_enable_hotplug);
518 struct v4l2_subdev *sd = &state->sd;
519
520 v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
521
522 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
523}
524
525static inline int edid_write_block(struct v4l2_subdev *sd, 513static inline int edid_write_block(struct v4l2_subdev *sd,
526 unsigned len, const u8 *val) 514 unsigned len, const u8 *val)
527{ 515{
528 struct i2c_client *client = v4l2_get_subdevdata(sd);
529 struct adv7604_state *state = to_state(sd); 516 struct adv7604_state *state = to_state(sd);
530 int err = 0; 517 int err = 0;
531 int i; 518 int i;
@@ -535,24 +522,19 @@ static inline int edid_write_block(struct v4l2_subdev *sd,
535 for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) 522 for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
536 err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, 523 err = adv_smbus_write_i2c_block_data(state->i2c_edid, i,
537 I2C_SMBUS_BLOCK_MAX, val + i); 524 I2C_SMBUS_BLOCK_MAX, val + i);
538 if (err) 525 return err;
539 return err; 526}
540 527
541 /* adv7604 calculates the checksums and enables I2C access to internal 528static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
542 EDID RAM from DDC port. */ 529{
543 rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); 530 struct delayed_work *dwork = to_delayed_work(work);
531 struct adv7604_state *state = container_of(dwork, struct adv7604_state,
532 delayed_work_enable_hotplug);
533 struct v4l2_subdev *sd = &state->sd;
544 534
545 for (i = 0; i < 1000; i++) { 535 v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
546 if (rep_read(sd, 0x7d) & state->edid.present)
547 break;
548 mdelay(1);
549 }
550 if (i == 1000) {
551 v4l_err(client, "error enabling edid (0x%x)\n", state->edid.present);
552 return -EIO;
553 }
554 536
555 return 0; 537 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
556} 538}
557 539
558static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) 540static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg)
@@ -1621,7 +1603,7 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
1621 return 0; 1603 return 0;
1622} 1604}
1623 1605
1624static int get_edid_spa_location(struct v4l2_subdev *sd, const u8 *edid) 1606static int get_edid_spa_location(const u8 *edid)
1625{ 1607{
1626 u8 d; 1608 u8 d;
1627 1609
@@ -1652,9 +1634,10 @@ static int get_edid_spa_location(struct v4l2_subdev *sd, const u8 *edid)
1652static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) 1634static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
1653{ 1635{
1654 struct adv7604_state *state = to_state(sd); 1636 struct adv7604_state *state = to_state(sd);
1655 int spa_loc = get_edid_spa_location(sd, edid->edid); 1637 int spa_loc;
1656 int tmp = 0; 1638 int tmp = 0;
1657 int err; 1639 int err;
1640 int i;
1658 1641
1659 if (edid->pad > ADV7604_EDID_PORT_D) 1642 if (edid->pad > ADV7604_EDID_PORT_D)
1660 return -EINVAL; 1643 return -EINVAL;
@@ -1684,35 +1667,43 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
1684 if (!edid->edid) 1667 if (!edid->edid)
1685 return -EINVAL; 1668 return -EINVAL;
1686 1669
1670 v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n",
1671 __func__, edid->pad, state->edid.present);
1672
1687 /* Disable hotplug and I2C access to EDID RAM from DDC port */ 1673 /* Disable hotplug and I2C access to EDID RAM from DDC port */
1688 cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); 1674 cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
1689 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp); 1675 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp);
1690 rep_write_and_or(sd, 0x77, 0xf0, 0x00); 1676 rep_write_and_or(sd, 0x77, 0xf0, 0x00);
1691 1677
1692 v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", 1678 spa_loc = get_edid_spa_location(edid->edid);
1693 __func__, edid->pad, state->edid.present); 1679 if (spa_loc < 0)
1680 spa_loc = 0xc0; /* Default value [REF_02, p. 116] */
1681
1694 switch (edid->pad) { 1682 switch (edid->pad) {
1695 case ADV7604_EDID_PORT_A: 1683 case ADV7604_EDID_PORT_A:
1696 state->spa_port_a = edid->edid[spa_loc]; 1684 state->spa_port_a[0] = edid->edid[spa_loc];
1685 state->spa_port_a[1] = edid->edid[spa_loc + 1];
1697 break; 1686 break;
1698 case ADV7604_EDID_PORT_B: 1687 case ADV7604_EDID_PORT_B:
1699 rep_write(sd, 0x70, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); 1688 rep_write(sd, 0x70, edid->edid[spa_loc]);
1700 rep_write(sd, 0x71, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); 1689 rep_write(sd, 0x71, edid->edid[spa_loc + 1]);
1701 break; 1690 break;
1702 case ADV7604_EDID_PORT_C: 1691 case ADV7604_EDID_PORT_C:
1703 rep_write(sd, 0x72, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); 1692 rep_write(sd, 0x72, edid->edid[spa_loc]);
1704 rep_write(sd, 0x73, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); 1693 rep_write(sd, 0x73, edid->edid[spa_loc + 1]);
1705 break; 1694 break;
1706 case ADV7604_EDID_PORT_D: 1695 case ADV7604_EDID_PORT_D:
1707 rep_write(sd, 0x74, (spa_loc < 0) ? 0 : edid->edid[spa_loc]); 1696 rep_write(sd, 0x74, edid->edid[spa_loc]);
1708 rep_write(sd, 0x75, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]); 1697 rep_write(sd, 0x75, edid->edid[spa_loc + 1]);
1709 break; 1698 break;
1699 default:
1700 return -EINVAL;
1710 } 1701 }
1711 rep_write(sd, 0x76, (spa_loc < 0) ? 0x00 : spa_loc); 1702 rep_write(sd, 0x76, spa_loc & 0xff);
1712 rep_write_and_or(sd, 0x77, 0xbf, (spa_loc < 0) ? 0x00 : (spa_loc >> 2) & 0x40); 1703 rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40);
1713 1704
1714 if (spa_loc > 0) 1705 edid->edid[spa_loc] = state->spa_port_a[0];
1715 edid->edid[spa_loc] = state->spa_port_a; 1706 edid->edid[spa_loc + 1] = state->spa_port_a[1];
1716 1707
1717 memcpy(state->edid.edid, edid->edid, 128 * edid->blocks); 1708 memcpy(state->edid.edid, edid->edid, 128 * edid->blocks);
1718 state->edid.blocks = edid->blocks; 1709 state->edid.blocks = edid->blocks;
@@ -1726,6 +1717,21 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
1726 return err; 1717 return err;
1727 } 1718 }
1728 1719
1720 /* adv7604 calculates the checksums and enables I2C access to internal
1721 EDID RAM from DDC port. */
1722 rep_write_and_or(sd, 0x77, 0xf0, state->edid.present);
1723
1724 for (i = 0; i < 1000; i++) {
1725 if (rep_read(sd, 0x7d) & state->edid.present)
1726 break;
1727 mdelay(1);
1728 }
1729 if (i == 1000) {
1730 v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present);
1731 return -EIO;
1732 }
1733
1734
1729 /* enable hotplug after 100 ms */ 1735 /* enable hotplug after 100 ms */
1730 queue_delayed_work(state->work_queues, 1736 queue_delayed_work(state->work_queues,
1731 &state->delayed_work_enable_hotplug, HZ / 10); 1737 &state->delayed_work_enable_hotplug, HZ / 10);