sun4i_hdmi_i2c.c (9222B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com> 4 * Copyright (C) 2017 Jonathan Liu <net147@gmail.com> 5 */ 6 7#include <linux/clk.h> 8#include <linux/i2c.h> 9#include <linux/iopoll.h> 10 11#include "sun4i_hdmi.h" 12 13#define SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK ( \ 14 SUN4I_HDMI_DDC_INT_STATUS_ILLEGAL_FIFO_OPERATION | \ 15 SUN4I_HDMI_DDC_INT_STATUS_DDC_RX_FIFO_UNDERFLOW | \ 16 SUN4I_HDMI_DDC_INT_STATUS_DDC_TX_FIFO_OVERFLOW | \ 17 SUN4I_HDMI_DDC_INT_STATUS_ARBITRATION_ERROR | \ 18 SUN4I_HDMI_DDC_INT_STATUS_ACK_ERROR | \ 19 SUN4I_HDMI_DDC_INT_STATUS_BUS_ERROR \ 20) 21 22/* FIFO request bit is set when FIFO level is above RX_THRESHOLD during read */ 23#define RX_THRESHOLD SUN4I_HDMI_DDC_FIFO_CTRL_RX_THRES_MAX 24 25static int fifo_transfer(struct sun4i_hdmi *hdmi, u8 *buf, int len, bool read) 26{ 27 /* 28 * 1 byte takes 9 clock cycles (8 bits + 1 ACK) = 90 us for 100 kHz 29 * clock. As clock rate is fixed, just round it up to 100 us. 30 */ 31 const unsigned long byte_time_ns = 100; 32 const u32 mask = SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK | 33 SUN4I_HDMI_DDC_INT_STATUS_FIFO_REQUEST | 34 SUN4I_HDMI_DDC_INT_STATUS_TRANSFER_COMPLETE; 35 u32 reg; 36 /* 37 * If threshold is inclusive, then the FIFO may only have 38 * RX_THRESHOLD number of bytes, instead of RX_THRESHOLD + 1. 39 */ 40 int read_len = RX_THRESHOLD + 41 (hdmi->variant->ddc_fifo_thres_incl ? 0 : 1); 42 43 /* 44 * Limit transfer length by FIFO threshold or FIFO size. 45 * For TX the threshold is for an empty FIFO. 46 */ 47 len = min_t(int, len, read ? read_len : SUN4I_HDMI_DDC_FIFO_SIZE); 48 49 /* Wait until error, FIFO request bit set or transfer complete */ 50 if (regmap_field_read_poll_timeout(hdmi->field_ddc_int_status, reg, 51 reg & mask, len * byte_time_ns, 52 100000)) 53 return -ETIMEDOUT; 54 55 if (reg & SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK) 56 return -EIO; 57 58 if (read) 59 ioread8_rep(hdmi->base + hdmi->variant->ddc_fifo_reg, buf, len); 60 else 61 iowrite8_rep(hdmi->base + hdmi->variant->ddc_fifo_reg, buf, len); 62 63 /* Clear FIFO request bit by forcing a write to that bit */ 64 regmap_field_force_write(hdmi->field_ddc_int_status, 65 SUN4I_HDMI_DDC_INT_STATUS_FIFO_REQUEST); 66 67 return len; 68} 69 70static int xfer_msg(struct sun4i_hdmi *hdmi, struct i2c_msg *msg) 71{ 72 int i, len; 73 u32 reg; 74 75 /* Set FIFO direction */ 76 if (hdmi->variant->ddc_fifo_has_dir) { 77 reg = readl(hdmi->base + SUN4I_HDMI_DDC_CTRL_REG); 78 reg &= ~SUN4I_HDMI_DDC_CTRL_FIFO_DIR_MASK; 79 reg |= (msg->flags & I2C_M_RD) ? 80 SUN4I_HDMI_DDC_CTRL_FIFO_DIR_READ : 81 SUN4I_HDMI_DDC_CTRL_FIFO_DIR_WRITE; 82 writel(reg, hdmi->base + SUN4I_HDMI_DDC_CTRL_REG); 83 } 84 85 /* Clear address register (not cleared by soft reset) */ 86 regmap_field_write(hdmi->field_ddc_addr_reg, 0); 87 88 /* Set I2C address */ 89 regmap_field_write(hdmi->field_ddc_slave_addr, msg->addr); 90 91 /* 92 * Set FIFO RX/TX thresholds and clear FIFO 93 * 94 * If threshold is inclusive, we can set the TX threshold to 95 * 0 instead of 1. 96 */ 97 regmap_field_write(hdmi->field_ddc_fifo_tx_thres, 98 hdmi->variant->ddc_fifo_thres_incl ? 0 : 1); 99 regmap_field_write(hdmi->field_ddc_fifo_rx_thres, RX_THRESHOLD); 100 regmap_field_write(hdmi->field_ddc_fifo_clear, 1); 101 if (regmap_field_read_poll_timeout(hdmi->field_ddc_fifo_clear, 102 reg, !reg, 100, 2000)) 103 return -EIO; 104 105 /* Set transfer length */ 106 regmap_field_write(hdmi->field_ddc_byte_count, msg->len); 107 108 /* Set command */ 109 regmap_field_write(hdmi->field_ddc_cmd, 110 msg->flags & I2C_M_RD ? 111 SUN4I_HDMI_DDC_CMD_IMPLICIT_READ : 112 SUN4I_HDMI_DDC_CMD_IMPLICIT_WRITE); 113 114 /* Clear interrupt status bits by forcing a write */ 115 regmap_field_force_write(hdmi->field_ddc_int_status, 116 SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK | 117 SUN4I_HDMI_DDC_INT_STATUS_FIFO_REQUEST | 118 SUN4I_HDMI_DDC_INT_STATUS_TRANSFER_COMPLETE); 119 120 /* Start command */ 121 regmap_field_write(hdmi->field_ddc_start, 1); 122 123 /* Transfer bytes */ 124 for (i = 0; i < msg->len; i += len) { 125 len = fifo_transfer(hdmi, msg->buf + i, msg->len - i, 126 msg->flags & I2C_M_RD); 127 if (len <= 0) 128 return len; 129 } 130 131 /* Wait for command to finish */ 132 if (regmap_field_read_poll_timeout(hdmi->field_ddc_start, 133 reg, !reg, 100, 100000)) 134 return -EIO; 135 136 /* Check for errors */ 137 regmap_field_read(hdmi->field_ddc_int_status, ®); 138 if ((reg & SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK) || 139 !(reg & SUN4I_HDMI_DDC_INT_STATUS_TRANSFER_COMPLETE)) { 140 return -EIO; 141 } 142 143 return 0; 144} 145 146static int sun4i_hdmi_i2c_xfer(struct i2c_adapter *adap, 147 struct i2c_msg *msgs, int num) 148{ 149 struct sun4i_hdmi *hdmi = i2c_get_adapdata(adap); 150 u32 reg; 151 int err, i, ret = num; 152 153 for (i = 0; i < num; i++) { 154 if (!msgs[i].len) 155 return -EINVAL; 156 if (msgs[i].len > SUN4I_HDMI_DDC_BYTE_COUNT_MAX) 157 return -EINVAL; 158 } 159 160 /* DDC clock needs to be enabled for the module to work */ 161 clk_prepare_enable(hdmi->ddc_clk); 162 clk_set_rate(hdmi->ddc_clk, 100000); 163 164 /* Reset I2C controller */ 165 regmap_field_write(hdmi->field_ddc_en, 1); 166 regmap_field_write(hdmi->field_ddc_reset, 1); 167 if (regmap_field_read_poll_timeout(hdmi->field_ddc_reset, 168 reg, !reg, 100, 2000)) { 169 clk_disable_unprepare(hdmi->ddc_clk); 170 return -EIO; 171 } 172 173 regmap_field_write(hdmi->field_ddc_sck_en, 1); 174 regmap_field_write(hdmi->field_ddc_sda_en, 1); 175 176 for (i = 0; i < num; i++) { 177 err = xfer_msg(hdmi, &msgs[i]); 178 if (err) { 179 ret = err; 180 break; 181 } 182 } 183 184 clk_disable_unprepare(hdmi->ddc_clk); 185 return ret; 186} 187 188static u32 sun4i_hdmi_i2c_func(struct i2c_adapter *adap) 189{ 190 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 191} 192 193static const struct i2c_algorithm sun4i_hdmi_i2c_algorithm = { 194 .master_xfer = sun4i_hdmi_i2c_xfer, 195 .functionality = sun4i_hdmi_i2c_func, 196}; 197 198static int sun4i_hdmi_init_regmap_fields(struct sun4i_hdmi *hdmi) 199{ 200 hdmi->field_ddc_en = 201 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 202 hdmi->variant->field_ddc_en); 203 if (IS_ERR(hdmi->field_ddc_en)) 204 return PTR_ERR(hdmi->field_ddc_en); 205 206 hdmi->field_ddc_start = 207 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 208 hdmi->variant->field_ddc_start); 209 if (IS_ERR(hdmi->field_ddc_start)) 210 return PTR_ERR(hdmi->field_ddc_start); 211 212 hdmi->field_ddc_reset = 213 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 214 hdmi->variant->field_ddc_reset); 215 if (IS_ERR(hdmi->field_ddc_reset)) 216 return PTR_ERR(hdmi->field_ddc_reset); 217 218 hdmi->field_ddc_addr_reg = 219 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 220 hdmi->variant->field_ddc_addr_reg); 221 if (IS_ERR(hdmi->field_ddc_addr_reg)) 222 return PTR_ERR(hdmi->field_ddc_addr_reg); 223 224 hdmi->field_ddc_slave_addr = 225 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 226 hdmi->variant->field_ddc_slave_addr); 227 if (IS_ERR(hdmi->field_ddc_slave_addr)) 228 return PTR_ERR(hdmi->field_ddc_slave_addr); 229 230 hdmi->field_ddc_int_mask = 231 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 232 hdmi->variant->field_ddc_int_mask); 233 if (IS_ERR(hdmi->field_ddc_int_mask)) 234 return PTR_ERR(hdmi->field_ddc_int_mask); 235 236 hdmi->field_ddc_int_status = 237 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 238 hdmi->variant->field_ddc_int_status); 239 if (IS_ERR(hdmi->field_ddc_int_status)) 240 return PTR_ERR(hdmi->field_ddc_int_status); 241 242 hdmi->field_ddc_fifo_clear = 243 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 244 hdmi->variant->field_ddc_fifo_clear); 245 if (IS_ERR(hdmi->field_ddc_fifo_clear)) 246 return PTR_ERR(hdmi->field_ddc_fifo_clear); 247 248 hdmi->field_ddc_fifo_rx_thres = 249 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 250 hdmi->variant->field_ddc_fifo_rx_thres); 251 if (IS_ERR(hdmi->field_ddc_fifo_rx_thres)) 252 return PTR_ERR(hdmi->field_ddc_fifo_rx_thres); 253 254 hdmi->field_ddc_fifo_tx_thres = 255 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 256 hdmi->variant->field_ddc_fifo_tx_thres); 257 if (IS_ERR(hdmi->field_ddc_fifo_tx_thres)) 258 return PTR_ERR(hdmi->field_ddc_fifo_tx_thres); 259 260 hdmi->field_ddc_byte_count = 261 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 262 hdmi->variant->field_ddc_byte_count); 263 if (IS_ERR(hdmi->field_ddc_byte_count)) 264 return PTR_ERR(hdmi->field_ddc_byte_count); 265 266 hdmi->field_ddc_cmd = 267 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 268 hdmi->variant->field_ddc_cmd); 269 if (IS_ERR(hdmi->field_ddc_cmd)) 270 return PTR_ERR(hdmi->field_ddc_cmd); 271 272 hdmi->field_ddc_sda_en = 273 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 274 hdmi->variant->field_ddc_sda_en); 275 if (IS_ERR(hdmi->field_ddc_sda_en)) 276 return PTR_ERR(hdmi->field_ddc_sda_en); 277 278 hdmi->field_ddc_sck_en = 279 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, 280 hdmi->variant->field_ddc_sck_en); 281 if (IS_ERR(hdmi->field_ddc_sck_en)) 282 return PTR_ERR(hdmi->field_ddc_sck_en); 283 284 return 0; 285} 286 287int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi) 288{ 289 struct i2c_adapter *adap; 290 int ret = 0; 291 292 ret = sun4i_ddc_create(hdmi, hdmi->ddc_parent_clk); 293 if (ret) 294 return ret; 295 296 ret = sun4i_hdmi_init_regmap_fields(hdmi); 297 if (ret) 298 return ret; 299 300 adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL); 301 if (!adap) 302 return -ENOMEM; 303 304 adap->owner = THIS_MODULE; 305 adap->class = I2C_CLASS_DDC; 306 adap->algo = &sun4i_hdmi_i2c_algorithm; 307 strlcpy(adap->name, "sun4i_hdmi_i2c adapter", sizeof(adap->name)); 308 i2c_set_adapdata(adap, hdmi); 309 310 ret = i2c_add_adapter(adap); 311 if (ret) 312 return ret; 313 314 hdmi->i2c = adap; 315 316 return ret; 317}