Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'dw-hdmi-next-2016-09-19' of git://git.pengutronix.de/git/pza/linux into drm-next

dw-hdmi i2c master controller

- add support for the HDMI I2C master controller, for boards that
can have their DDC pins connected only to the HDMI TX directly.

* tag 'dw-hdmi-next-2016-09-19' of git://git.pengutronix.de/git/pza/linux:
drm: bridge/dw_hdmi: add dw hdmi i2c bus adapter support
drm: dw_hdmi: use of_get_i2c_adapter_by_node interface

+290 -12
+3 -1
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt
··· 19 19 20 20 Optional properties 21 21 - reg-io-width: the width of the reg:1,4, default set to 1 if not present 22 - - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing 22 + - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing, 23 + if the property is omitted, a functionally reduced I2C bus 24 + controller on DW HDMI is probed 23 25 - clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec" 24 26 25 27 Example:
+268 -11
drivers/gpu/drm/bridge/dw-hdmi.c
··· 1 1 /* 2 + * DesignWare High-Definition Multimedia Interface (HDMI) driver 3 + * 4 + * Copyright (C) 2013-2015 Mentor Graphics Inc. 2 5 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 6 + * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> 3 7 * 4 8 * This program is free software; you can redistribute it and/or modify 5 9 * it under the terms of the GNU General Public License as published by 6 10 * the Free Software Foundation; either version 2 of the License, or 7 11 * (at your option) any later version. 8 12 * 9 - * Designware High-Definition Multimedia Interface (HDMI) driver 10 - * 11 - * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> 12 13 */ 13 14 #include <linux/module.h> 14 15 #include <linux/irq.h> ··· 102 101 struct hdmi_vmode video_mode; 103 102 }; 104 103 104 + struct dw_hdmi_i2c { 105 + struct i2c_adapter adap; 106 + 107 + struct mutex lock; /* used to serialize data transfers */ 108 + struct completion cmp; 109 + u8 stat; 110 + 111 + u8 slave_reg; 112 + bool is_regaddr; 113 + }; 114 + 105 115 struct dw_hdmi { 106 116 struct drm_connector connector; 107 117 struct drm_encoder *encoder; ··· 123 111 struct device *dev; 124 112 struct clk *isfr_clk; 125 113 struct clk *iahb_clk; 114 + struct dw_hdmi_i2c *i2c; 126 115 127 116 struct hdmi_data_info hdmi_data; 128 117 const struct dw_hdmi_plat_data *plat_data; ··· 209 196 u8 shift, u8 mask) 210 197 { 211 198 hdmi_modb(hdmi, data << shift, mask, reg); 199 + } 200 + 201 + static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi) 202 + { 203 + /* Software reset */ 204 + hdmi_writeb(hdmi, 0x00, HDMI_I2CM_SOFTRSTZ); 205 + 206 + /* Set Standard Mode speed (determined to be 100KHz on iMX6) */ 207 + hdmi_writeb(hdmi, 0x00, HDMI_I2CM_DIV); 208 + 209 + /* Set done, not acknowledged and arbitration interrupt polarities */ 210 + hdmi_writeb(hdmi, HDMI_I2CM_INT_DONE_POL, HDMI_I2CM_INT); 211 + hdmi_writeb(hdmi, HDMI_I2CM_CTLINT_NAC_POL | HDMI_I2CM_CTLINT_ARB_POL, 212 + HDMI_I2CM_CTLINT); 213 + 214 + /* Clear DONE and ERROR interrupts */ 215 + hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE, 216 + HDMI_IH_I2CM_STAT0); 217 + 218 + /* Mute DONE and ERROR interrupts */ 219 + hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE, 220 + HDMI_IH_MUTE_I2CM_STAT0); 221 + } 222 + 223 + static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi, 224 + unsigned char *buf, unsigned int length) 225 + { 226 + struct dw_hdmi_i2c *i2c = hdmi->i2c; 227 + int stat; 228 + 229 + if (!i2c->is_regaddr) { 230 + dev_dbg(hdmi->dev, "set read register address to 0\n"); 231 + i2c->slave_reg = 0x00; 232 + i2c->is_regaddr = true; 233 + } 234 + 235 + while (length--) { 236 + reinit_completion(&i2c->cmp); 237 + 238 + hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS); 239 + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ, 240 + HDMI_I2CM_OPERATION); 241 + 242 + stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); 243 + if (!stat) 244 + return -EAGAIN; 245 + 246 + /* Check for error condition on the bus */ 247 + if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) 248 + return -EIO; 249 + 250 + *buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI); 251 + } 252 + 253 + return 0; 254 + } 255 + 256 + static int dw_hdmi_i2c_write(struct dw_hdmi *hdmi, 257 + unsigned char *buf, unsigned int length) 258 + { 259 + struct dw_hdmi_i2c *i2c = hdmi->i2c; 260 + int stat; 261 + 262 + if (!i2c->is_regaddr) { 263 + /* Use the first write byte as register address */ 264 + i2c->slave_reg = buf[0]; 265 + length--; 266 + buf++; 267 + i2c->is_regaddr = true; 268 + } 269 + 270 + while (length--) { 271 + reinit_completion(&i2c->cmp); 272 + 273 + hdmi_writeb(hdmi, *buf++, HDMI_I2CM_DATAO); 274 + hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS); 275 + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_WRITE, 276 + HDMI_I2CM_OPERATION); 277 + 278 + stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); 279 + if (!stat) 280 + return -EAGAIN; 281 + 282 + /* Check for error condition on the bus */ 283 + if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) 284 + return -EIO; 285 + } 286 + 287 + return 0; 288 + } 289 + 290 + static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap, 291 + struct i2c_msg *msgs, int num) 292 + { 293 + struct dw_hdmi *hdmi = i2c_get_adapdata(adap); 294 + struct dw_hdmi_i2c *i2c = hdmi->i2c; 295 + u8 addr = msgs[0].addr; 296 + int i, ret = 0; 297 + 298 + dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr); 299 + 300 + for (i = 0; i < num; i++) { 301 + if (msgs[i].addr != addr) { 302 + dev_warn(hdmi->dev, 303 + "unsupported transfer, changed slave address\n"); 304 + return -EOPNOTSUPP; 305 + } 306 + 307 + if (msgs[i].len == 0) { 308 + dev_dbg(hdmi->dev, 309 + "unsupported transfer %d/%d, no data\n", 310 + i + 1, num); 311 + return -EOPNOTSUPP; 312 + } 313 + } 314 + 315 + mutex_lock(&i2c->lock); 316 + 317 + /* Unmute DONE and ERROR interrupts */ 318 + hdmi_writeb(hdmi, 0x00, HDMI_IH_MUTE_I2CM_STAT0); 319 + 320 + /* Set slave device address taken from the first I2C message */ 321 + hdmi_writeb(hdmi, addr, HDMI_I2CM_SLAVE); 322 + 323 + /* Set slave device register address on transfer */ 324 + i2c->is_regaddr = false; 325 + 326 + for (i = 0; i < num; i++) { 327 + dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n", 328 + i + 1, num, msgs[i].len, msgs[i].flags); 329 + 330 + if (msgs[i].flags & I2C_M_RD) 331 + ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf, msgs[i].len); 332 + else 333 + ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf, msgs[i].len); 334 + 335 + if (ret < 0) 336 + break; 337 + } 338 + 339 + if (!ret) 340 + ret = num; 341 + 342 + /* Mute DONE and ERROR interrupts */ 343 + hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE, 344 + HDMI_IH_MUTE_I2CM_STAT0); 345 + 346 + mutex_unlock(&i2c->lock); 347 + 348 + return ret; 349 + } 350 + 351 + static u32 dw_hdmi_i2c_func(struct i2c_adapter *adapter) 352 + { 353 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 354 + } 355 + 356 + static const struct i2c_algorithm dw_hdmi_algorithm = { 357 + .master_xfer = dw_hdmi_i2c_xfer, 358 + .functionality = dw_hdmi_i2c_func, 359 + }; 360 + 361 + static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi) 362 + { 363 + struct i2c_adapter *adap; 364 + struct dw_hdmi_i2c *i2c; 365 + int ret; 366 + 367 + i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); 368 + if (!i2c) 369 + return ERR_PTR(-ENOMEM); 370 + 371 + mutex_init(&i2c->lock); 372 + init_completion(&i2c->cmp); 373 + 374 + adap = &i2c->adap; 375 + adap->class = I2C_CLASS_DDC; 376 + adap->owner = THIS_MODULE; 377 + adap->dev.parent = hdmi->dev; 378 + adap->algo = &dw_hdmi_algorithm; 379 + strlcpy(adap->name, "DesignWare HDMI", sizeof(adap->name)); 380 + i2c_set_adapdata(adap, hdmi); 381 + 382 + ret = i2c_add_adapter(adap); 383 + if (ret) { 384 + dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); 385 + devm_kfree(hdmi->dev, i2c); 386 + return ERR_PTR(ret); 387 + } 388 + 389 + hdmi->i2c = i2c; 390 + 391 + dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); 392 + 393 + return adap; 212 394 } 213 395 214 396 static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, ··· 1720 1512 .mode_set = dw_hdmi_bridge_mode_set, 1721 1513 }; 1722 1514 1515 + static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi) 1516 + { 1517 + struct dw_hdmi_i2c *i2c = hdmi->i2c; 1518 + unsigned int stat; 1519 + 1520 + stat = hdmi_readb(hdmi, HDMI_IH_I2CM_STAT0); 1521 + if (!stat) 1522 + return IRQ_NONE; 1523 + 1524 + hdmi_writeb(hdmi, stat, HDMI_IH_I2CM_STAT0); 1525 + 1526 + i2c->stat = stat; 1527 + 1528 + complete(&i2c->cmp); 1529 + 1530 + return IRQ_HANDLED; 1531 + } 1532 + 1723 1533 static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) 1724 1534 { 1725 1535 struct dw_hdmi *hdmi = dev_id; 1726 1536 u8 intr_stat; 1537 + irqreturn_t ret = IRQ_NONE; 1538 + 1539 + if (hdmi->i2c) 1540 + ret = dw_hdmi_i2c_irq(hdmi); 1727 1541 1728 1542 intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); 1729 - if (intr_stat) 1543 + if (intr_stat) { 1730 1544 hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); 1545 + return IRQ_WAKE_THREAD; 1546 + } 1731 1547 1732 - return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE; 1548 + return ret; 1733 1549 } 1734 1550 1735 1551 static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) ··· 1913 1681 1914 1682 ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); 1915 1683 if (ddc_node) { 1916 - hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); 1684 + hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); 1917 1685 of_node_put(ddc_node); 1918 1686 if (!hdmi->ddc) { 1919 1687 dev_dbg(hdmi->dev, "failed to read ddc node\n"); ··· 1925 1693 } 1926 1694 1927 1695 hdmi->regs = devm_ioremap_resource(dev, iores); 1928 - if (IS_ERR(hdmi->regs)) 1929 - return PTR_ERR(hdmi->regs); 1696 + if (IS_ERR(hdmi->regs)) { 1697 + ret = PTR_ERR(hdmi->regs); 1698 + goto err_res; 1699 + } 1930 1700 1931 1701 hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); 1932 1702 if (IS_ERR(hdmi->isfr_clk)) { 1933 1703 ret = PTR_ERR(hdmi->isfr_clk); 1934 1704 dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret); 1935 - return ret; 1705 + goto err_res; 1936 1706 } 1937 1707 1938 1708 ret = clk_prepare_enable(hdmi->isfr_clk); 1939 1709 if (ret) { 1940 1710 dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret); 1941 - return ret; 1711 + goto err_res; 1942 1712 } 1943 1713 1944 1714 hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); ··· 1977 1743 * N and cts values before enabling phy 1978 1744 */ 1979 1745 hdmi_init_clk_regenerator(hdmi); 1746 + 1747 + /* If DDC bus is not specified, try to register HDMI I2C bus */ 1748 + if (!hdmi->ddc) { 1749 + hdmi->ddc = dw_hdmi_i2c_adapter(hdmi); 1750 + if (IS_ERR(hdmi->ddc)) 1751 + hdmi->ddc = NULL; 1752 + } 1980 1753 1981 1754 /* 1982 1755 * Configure registers related to HDMI interrupt ··· 2025 1784 hdmi->audio = platform_device_register_full(&pdevinfo); 2026 1785 } 2027 1786 1787 + /* Reset HDMI DDC I2C master controller and mute I2CM interrupts */ 1788 + if (hdmi->i2c) 1789 + dw_hdmi_i2c_init(hdmi); 1790 + 2028 1791 dev_set_drvdata(dev, hdmi); 2029 1792 2030 1793 return 0; 2031 1794 2032 1795 err_iahb: 1796 + if (hdmi->i2c) { 1797 + i2c_del_adapter(&hdmi->i2c->adap); 1798 + hdmi->ddc = NULL; 1799 + } 1800 + 2033 1801 clk_disable_unprepare(hdmi->iahb_clk); 2034 1802 err_isfr: 2035 1803 clk_disable_unprepare(hdmi->isfr_clk); 1804 + err_res: 1805 + i2c_put_adapter(hdmi->ddc); 2036 1806 2037 1807 return ret; 2038 1808 } ··· 2061 1809 2062 1810 clk_disable_unprepare(hdmi->iahb_clk); 2063 1811 clk_disable_unprepare(hdmi->isfr_clk); 2064 - i2c_put_adapter(hdmi->ddc); 1812 + 1813 + if (hdmi->i2c) 1814 + i2c_del_adapter(&hdmi->i2c->adap); 1815 + else 1816 + i2c_put_adapter(hdmi->ddc); 2065 1817 } 2066 1818 EXPORT_SYMBOL_GPL(dw_hdmi_unbind); 2067 1819 2068 1820 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 2069 1821 MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); 2070 1822 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); 1823 + MODULE_AUTHOR("Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>"); 2071 1824 MODULE_DESCRIPTION("DW HDMI transmitter driver"); 2072 1825 MODULE_LICENSE("GPL"); 2073 1826 MODULE_ALIAS("platform:dw-hdmi");
+19
drivers/gpu/drm/bridge/dw-hdmi.h
··· 566 566 HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2, 567 567 HDMI_IH_PHY_STAT0_HPD = 0x1, 568 568 569 + /* IH_I2CM_STAT0 and IH_MUTE_I2CM_STAT0 field values */ 570 + HDMI_IH_I2CM_STAT0_DONE = 0x2, 571 + HDMI_IH_I2CM_STAT0_ERROR = 0x1, 572 + 569 573 /* IH_MUTE_I2CMPHY_STAT0 field values */ 570 574 HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2, 571 575 HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1, ··· 1036 1032 HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2, 1037 1033 HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2, 1038 1034 HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0, 1035 + 1036 + /* I2CM_OPERATION field values */ 1037 + HDMI_I2CM_OPERATION_WRITE = 0x10, 1038 + HDMI_I2CM_OPERATION_READ_EXT = 0x2, 1039 + HDMI_I2CM_OPERATION_READ = 0x1, 1040 + 1041 + /* I2CM_INT field values */ 1042 + HDMI_I2CM_INT_DONE_POL = 0x8, 1043 + HDMI_I2CM_INT_DONE_MASK = 0x4, 1044 + 1045 + /* I2CM_CTLINT field values */ 1046 + HDMI_I2CM_CTLINT_NAC_POL = 0x80, 1047 + HDMI_I2CM_CTLINT_NAC_MASK = 0x40, 1048 + HDMI_I2CM_CTLINT_ARB_POL = 0x8, 1049 + HDMI_I2CM_CTLINT_ARB_MASK = 0x4, 1039 1050 }; 1040 1051 1041 1052 #endif /* __DW_HDMI_H__ */