mtk_hdmi_ddc.c (8849B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2014 MediaTek Inc. 4 * Author: Jie Qiu <jie.qiu@mediatek.com> 5 */ 6#include <linux/kernel.h> 7#include <linux/module.h> 8#include <linux/i2c.h> 9#include <linux/time.h> 10#include <linux/delay.h> 11#include <linux/errno.h> 12#include <linux/err.h> 13#include <linux/platform_device.h> 14#include <linux/clk.h> 15#include <linux/slab.h> 16#include <linux/io.h> 17#include <linux/iopoll.h> 18#include <linux/of_address.h> 19#include <linux/of_irq.h> 20#include <linux/of_platform.h> 21 22#define SIF1_CLOK (288) 23#define DDC_DDCMCTL0 (0x0) 24#define DDCM_ODRAIN BIT(31) 25#define DDCM_CLK_DIV_OFFSET (16) 26#define DDCM_CLK_DIV_MASK (0xfff << 16) 27#define DDCM_CS_STATUS BIT(4) 28#define DDCM_SCL_STATE BIT(3) 29#define DDCM_SDA_STATE BIT(2) 30#define DDCM_SM0EN BIT(1) 31#define DDCM_SCL_STRECH BIT(0) 32#define DDC_DDCMCTL1 (0x4) 33#define DDCM_ACK_OFFSET (16) 34#define DDCM_ACK_MASK (0xff << 16) 35#define DDCM_PGLEN_OFFSET (8) 36#define DDCM_PGLEN_MASK (0x7 << 8) 37#define DDCM_SIF_MODE_OFFSET (4) 38#define DDCM_SIF_MODE_MASK (0x7 << 4) 39#define DDCM_START (0x1) 40#define DDCM_WRITE_DATA (0x2) 41#define DDCM_STOP (0x3) 42#define DDCM_READ_DATA_NO_ACK (0x4) 43#define DDCM_READ_DATA_ACK (0x5) 44#define DDCM_TRI BIT(0) 45#define DDC_DDCMD0 (0x8) 46#define DDCM_DATA3 (0xff << 24) 47#define DDCM_DATA2 (0xff << 16) 48#define DDCM_DATA1 (0xff << 8) 49#define DDCM_DATA0 (0xff << 0) 50#define DDC_DDCMD1 (0xc) 51#define DDCM_DATA7 (0xff << 24) 52#define DDCM_DATA6 (0xff << 16) 53#define DDCM_DATA5 (0xff << 8) 54#define DDCM_DATA4 (0xff << 0) 55 56struct mtk_hdmi_ddc { 57 struct i2c_adapter adap; 58 struct clk *clk; 59 void __iomem *regs; 60}; 61 62static inline void sif_set_bit(struct mtk_hdmi_ddc *ddc, unsigned int offset, 63 unsigned int val) 64{ 65 writel(readl(ddc->regs + offset) | val, ddc->regs + offset); 66} 67 68static inline void sif_clr_bit(struct mtk_hdmi_ddc *ddc, unsigned int offset, 69 unsigned int val) 70{ 71 writel(readl(ddc->regs + offset) & ~val, ddc->regs + offset); 72} 73 74static inline bool sif_bit_is_set(struct mtk_hdmi_ddc *ddc, unsigned int offset, 75 unsigned int val) 76{ 77 return (readl(ddc->regs + offset) & val) == val; 78} 79 80static inline void sif_write_mask(struct mtk_hdmi_ddc *ddc, unsigned int offset, 81 unsigned int mask, unsigned int shift, 82 unsigned int val) 83{ 84 unsigned int tmp; 85 86 tmp = readl(ddc->regs + offset); 87 tmp &= ~mask; 88 tmp |= (val << shift) & mask; 89 writel(tmp, ddc->regs + offset); 90} 91 92static inline unsigned int sif_read_mask(struct mtk_hdmi_ddc *ddc, 93 unsigned int offset, unsigned int mask, 94 unsigned int shift) 95{ 96 return (readl(ddc->regs + offset) & mask) >> shift; 97} 98 99static void ddcm_trigger_mode(struct mtk_hdmi_ddc *ddc, int mode) 100{ 101 u32 val; 102 103 sif_write_mask(ddc, DDC_DDCMCTL1, DDCM_SIF_MODE_MASK, 104 DDCM_SIF_MODE_OFFSET, mode); 105 sif_set_bit(ddc, DDC_DDCMCTL1, DDCM_TRI); 106 readl_poll_timeout(ddc->regs + DDC_DDCMCTL1, val, 107 (val & DDCM_TRI) != DDCM_TRI, 4, 20000); 108} 109 110static int mtk_hdmi_ddc_read_msg(struct mtk_hdmi_ddc *ddc, struct i2c_msg *msg) 111{ 112 struct device *dev = ddc->adap.dev.parent; 113 u32 remain_count, ack_count, ack_final, read_count, temp_count; 114 u32 index = 0; 115 u32 ack; 116 int i; 117 118 ddcm_trigger_mode(ddc, DDCM_START); 119 sif_write_mask(ddc, DDC_DDCMD0, 0xff, 0, (msg->addr << 1) | 0x01); 120 sif_write_mask(ddc, DDC_DDCMCTL1, DDCM_PGLEN_MASK, DDCM_PGLEN_OFFSET, 121 0x00); 122 ddcm_trigger_mode(ddc, DDCM_WRITE_DATA); 123 ack = sif_read_mask(ddc, DDC_DDCMCTL1, DDCM_ACK_MASK, DDCM_ACK_OFFSET); 124 dev_dbg(dev, "ack = 0x%x\n", ack); 125 if (ack != 0x01) { 126 dev_err(dev, "i2c ack err!\n"); 127 return -ENXIO; 128 } 129 130 remain_count = msg->len; 131 ack_count = (msg->len - 1) / 8; 132 ack_final = 0; 133 134 while (remain_count > 0) { 135 if (ack_count > 0) { 136 read_count = 8; 137 ack_final = 0; 138 ack_count--; 139 } else { 140 read_count = remain_count; 141 ack_final = 1; 142 } 143 144 sif_write_mask(ddc, DDC_DDCMCTL1, DDCM_PGLEN_MASK, 145 DDCM_PGLEN_OFFSET, read_count - 1); 146 ddcm_trigger_mode(ddc, (ack_final == 1) ? 147 DDCM_READ_DATA_NO_ACK : 148 DDCM_READ_DATA_ACK); 149 150 ack = sif_read_mask(ddc, DDC_DDCMCTL1, DDCM_ACK_MASK, 151 DDCM_ACK_OFFSET); 152 temp_count = 0; 153 while (((ack & (1 << temp_count)) != 0) && (temp_count < 8)) 154 temp_count++; 155 if (((ack_final == 1) && (temp_count != (read_count - 1))) || 156 ((ack_final == 0) && (temp_count != read_count))) { 157 dev_err(dev, "Address NACK! ACK(0x%x)\n", ack); 158 break; 159 } 160 161 for (i = read_count; i >= 1; i--) { 162 int shift; 163 int offset; 164 165 if (i > 4) { 166 offset = DDC_DDCMD1; 167 shift = (i - 5) * 8; 168 } else { 169 offset = DDC_DDCMD0; 170 shift = (i - 1) * 8; 171 } 172 173 msg->buf[index + i - 1] = sif_read_mask(ddc, offset, 174 0xff << shift, 175 shift); 176 } 177 178 remain_count -= read_count; 179 index += read_count; 180 } 181 182 return 0; 183} 184 185static int mtk_hdmi_ddc_write_msg(struct mtk_hdmi_ddc *ddc, struct i2c_msg *msg) 186{ 187 struct device *dev = ddc->adap.dev.parent; 188 u32 ack; 189 190 ddcm_trigger_mode(ddc, DDCM_START); 191 sif_write_mask(ddc, DDC_DDCMD0, DDCM_DATA0, 0, msg->addr << 1); 192 sif_write_mask(ddc, DDC_DDCMD0, DDCM_DATA1, 8, msg->buf[0]); 193 sif_write_mask(ddc, DDC_DDCMCTL1, DDCM_PGLEN_MASK, DDCM_PGLEN_OFFSET, 194 0x1); 195 ddcm_trigger_mode(ddc, DDCM_WRITE_DATA); 196 197 ack = sif_read_mask(ddc, DDC_DDCMCTL1, DDCM_ACK_MASK, DDCM_ACK_OFFSET); 198 dev_dbg(dev, "ack = %d\n", ack); 199 200 if (ack != 0x03) { 201 dev_err(dev, "i2c ack err!\n"); 202 return -EIO; 203 } 204 205 return 0; 206} 207 208static int mtk_hdmi_ddc_xfer(struct i2c_adapter *adapter, 209 struct i2c_msg *msgs, int num) 210{ 211 struct mtk_hdmi_ddc *ddc = adapter->algo_data; 212 struct device *dev = adapter->dev.parent; 213 int ret; 214 int i; 215 216 if (!ddc) { 217 dev_err(dev, "invalid arguments\n"); 218 return -EINVAL; 219 } 220 221 sif_set_bit(ddc, DDC_DDCMCTL0, DDCM_SCL_STRECH); 222 sif_set_bit(ddc, DDC_DDCMCTL0, DDCM_SM0EN); 223 sif_clr_bit(ddc, DDC_DDCMCTL0, DDCM_ODRAIN); 224 225 if (sif_bit_is_set(ddc, DDC_DDCMCTL1, DDCM_TRI)) { 226 dev_err(dev, "ddc line is busy!\n"); 227 return -EBUSY; 228 } 229 230 sif_write_mask(ddc, DDC_DDCMCTL0, DDCM_CLK_DIV_MASK, 231 DDCM_CLK_DIV_OFFSET, SIF1_CLOK); 232 233 for (i = 0; i < num; i++) { 234 struct i2c_msg *msg = &msgs[i]; 235 236 dev_dbg(dev, "i2c msg, adr:0x%x, flags:%d, len :0x%x\n", 237 msg->addr, msg->flags, msg->len); 238 239 if (msg->flags & I2C_M_RD) 240 ret = mtk_hdmi_ddc_read_msg(ddc, msg); 241 else 242 ret = mtk_hdmi_ddc_write_msg(ddc, msg); 243 if (ret < 0) 244 goto xfer_end; 245 } 246 247 ddcm_trigger_mode(ddc, DDCM_STOP); 248 249 return i; 250 251xfer_end: 252 ddcm_trigger_mode(ddc, DDCM_STOP); 253 dev_err(dev, "ddc failed!\n"); 254 return ret; 255} 256 257static u32 mtk_hdmi_ddc_func(struct i2c_adapter *adapter) 258{ 259 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 260} 261 262static const struct i2c_algorithm mtk_hdmi_ddc_algorithm = { 263 .master_xfer = mtk_hdmi_ddc_xfer, 264 .functionality = mtk_hdmi_ddc_func, 265}; 266 267static int mtk_hdmi_ddc_probe(struct platform_device *pdev) 268{ 269 struct device *dev = &pdev->dev; 270 struct mtk_hdmi_ddc *ddc; 271 struct resource *mem; 272 int ret; 273 274 ddc = devm_kzalloc(dev, sizeof(struct mtk_hdmi_ddc), GFP_KERNEL); 275 if (!ddc) 276 return -ENOMEM; 277 278 ddc->clk = devm_clk_get(dev, "ddc-i2c"); 279 if (IS_ERR(ddc->clk)) { 280 dev_err(dev, "get ddc_clk failed: %p ,\n", ddc->clk); 281 return PTR_ERR(ddc->clk); 282 } 283 284 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 285 ddc->regs = devm_ioremap_resource(&pdev->dev, mem); 286 if (IS_ERR(ddc->regs)) 287 return PTR_ERR(ddc->regs); 288 289 ret = clk_prepare_enable(ddc->clk); 290 if (ret) { 291 dev_err(dev, "enable ddc clk failed!\n"); 292 return ret; 293 } 294 295 strlcpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name)); 296 ddc->adap.owner = THIS_MODULE; 297 ddc->adap.class = I2C_CLASS_DDC; 298 ddc->adap.algo = &mtk_hdmi_ddc_algorithm; 299 ddc->adap.retries = 3; 300 ddc->adap.dev.of_node = dev->of_node; 301 ddc->adap.algo_data = ddc; 302 ddc->adap.dev.parent = &pdev->dev; 303 304 ret = i2c_add_adapter(&ddc->adap); 305 if (ret < 0) { 306 dev_err(dev, "failed to add bus to i2c core\n"); 307 goto err_clk_disable; 308 } 309 310 platform_set_drvdata(pdev, ddc); 311 312 dev_dbg(dev, "ddc->adap: %p\n", &ddc->adap); 313 dev_dbg(dev, "ddc->clk: %p\n", ddc->clk); 314 dev_dbg(dev, "physical adr: %pa, end: %pa\n", &mem->start, 315 &mem->end); 316 317 return 0; 318 319err_clk_disable: 320 clk_disable_unprepare(ddc->clk); 321 return ret; 322} 323 324static int mtk_hdmi_ddc_remove(struct platform_device *pdev) 325{ 326 struct mtk_hdmi_ddc *ddc = platform_get_drvdata(pdev); 327 328 i2c_del_adapter(&ddc->adap); 329 clk_disable_unprepare(ddc->clk); 330 331 return 0; 332} 333 334static const struct of_device_id mtk_hdmi_ddc_match[] = { 335 { .compatible = "mediatek,mt8173-hdmi-ddc", }, 336 {}, 337}; 338MODULE_DEVICE_TABLE(of, mtk_hdmi_ddc_match); 339 340struct platform_driver mtk_hdmi_ddc_driver = { 341 .probe = mtk_hdmi_ddc_probe, 342 .remove = mtk_hdmi_ddc_remove, 343 .driver = { 344 .name = "mediatek-hdmi-ddc", 345 .of_match_table = mtk_hdmi_ddc_match, 346 }, 347}; 348 349MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>"); 350MODULE_DESCRIPTION("MediaTek HDMI DDC Driver"); 351MODULE_LICENSE("GPL v2");