1/* 2 * Copyright (C) 2013 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18#include "hdmi.h" 19 20struct hdmi_i2c_adapter { 21 struct i2c_adapter base; 22 struct hdmi *hdmi; 23 bool sw_done; 24 wait_queue_head_t ddc_event; 25}; 26#define to_hdmi_i2c_adapter(x) container_of(x, struct hdmi_i2c_adapter, base) 27 28static void init_ddc(struct hdmi_i2c_adapter *hdmi_i2c) 29{ 30 struct hdmi *hdmi = hdmi_i2c->hdmi; 31 32 hdmi_write(hdmi, REG_HDMI_DDC_CTRL, 33 HDMI_DDC_CTRL_SW_STATUS_RESET); 34 hdmi_write(hdmi, REG_HDMI_DDC_CTRL, 35 HDMI_DDC_CTRL_SOFT_RESET); 36 37 hdmi_write(hdmi, REG_HDMI_DDC_SPEED, 38 HDMI_DDC_SPEED_THRESHOLD(2) | 39 HDMI_DDC_SPEED_PRESCALE(10)); 40 41 hdmi_write(hdmi, REG_HDMI_DDC_SETUP, 42 HDMI_DDC_SETUP_TIMEOUT(0xff)); 43 44 /* enable reference timer for 27us */ 45 hdmi_write(hdmi, REG_HDMI_DDC_REF, 46 HDMI_DDC_REF_REFTIMER_ENABLE | 47 HDMI_DDC_REF_REFTIMER(27)); 48} 49 50static int ddc_clear_irq(struct hdmi_i2c_adapter *hdmi_i2c) 51{ 52 struct hdmi *hdmi = hdmi_i2c->hdmi; 53 struct drm_device *dev = hdmi->dev; 54 uint32_t retry = 0xffff; 55 uint32_t ddc_int_ctrl; 56 57 do { 58 --retry; 59 60 hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL, 61 HDMI_DDC_INT_CTRL_SW_DONE_ACK | 62 HDMI_DDC_INT_CTRL_SW_DONE_MASK); 63 64 ddc_int_ctrl = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL); 65 66 } while ((ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_INT) && retry); 67 68 if (!retry) { 69 dev_err(dev->dev, "timeout waiting for DDC\n"); 70 return -ETIMEDOUT; 71 } 72 73 hdmi_i2c->sw_done = false; 74 75 return 0; 76} 77 78#define MAX_TRANSACTIONS 4 79 80static bool sw_done(struct hdmi_i2c_adapter *hdmi_i2c) 81{ 82 struct hdmi *hdmi = hdmi_i2c->hdmi; 83 84 if (!hdmi_i2c->sw_done) { 85 uint32_t ddc_int_ctrl; 86 87 ddc_int_ctrl = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL); 88 89 if ((ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_MASK) && 90 (ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_INT)) { 91 hdmi_i2c->sw_done = true; 92 hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL, 93 HDMI_DDC_INT_CTRL_SW_DONE_ACK); 94 } 95 } 96 97 return hdmi_i2c->sw_done; 98} 99 100static int hdmi_i2c_xfer(struct i2c_adapter *i2c, 101 struct i2c_msg *msgs, int num) 102{ 103 struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(i2c); 104 struct hdmi *hdmi = hdmi_i2c->hdmi; 105 struct drm_device *dev = hdmi->dev; 106 static const uint32_t nack[] = { 107 HDMI_DDC_SW_STATUS_NACK0, HDMI_DDC_SW_STATUS_NACK1, 108 HDMI_DDC_SW_STATUS_NACK2, HDMI_DDC_SW_STATUS_NACK3, 109 }; 110 int indices[MAX_TRANSACTIONS]; 111 int ret, i, j, index = 0; 112 uint32_t ddc_status, ddc_data, i2c_trans; 113 114 num = min(num, MAX_TRANSACTIONS); 115 116 WARN_ON(!(hdmi_read(hdmi, REG_HDMI_CTRL) & HDMI_CTRL_ENABLE)); 117 118 if (num == 0) 119 return num; 120 121 init_ddc(hdmi_i2c); 122 123 ret = ddc_clear_irq(hdmi_i2c); 124 if (ret) 125 return ret; 126 127 for (i = 0; i < num; i++) { 128 struct i2c_msg *p = &msgs[i]; 129 uint32_t raw_addr = p->addr << 1; 130 131 if (p->flags & I2C_M_RD) 132 raw_addr |= 1; 133 134 ddc_data = HDMI_DDC_DATA_DATA(raw_addr) | 135 HDMI_DDC_DATA_DATA_RW(DDC_WRITE); 136 137 if (i == 0) { 138 ddc_data |= HDMI_DDC_DATA_INDEX(0) | 139 HDMI_DDC_DATA_INDEX_WRITE; 140 } 141 142 hdmi_write(hdmi, REG_HDMI_DDC_DATA, ddc_data); 143 index++; 144 145 indices[i] = index; 146 147 if (p->flags & I2C_M_RD) { 148 index += p->len; 149 } else { 150 for (j = 0; j < p->len; j++) { 151 ddc_data = HDMI_DDC_DATA_DATA(p->buf[j]) | 152 HDMI_DDC_DATA_DATA_RW(DDC_WRITE); 153 hdmi_write(hdmi, REG_HDMI_DDC_DATA, ddc_data); 154 index++; 155 } 156 } 157 158 i2c_trans = HDMI_I2C_TRANSACTION_REG_CNT(p->len) | 159 HDMI_I2C_TRANSACTION_REG_RW( 160 (p->flags & I2C_M_RD) ? DDC_READ : DDC_WRITE) | 161 HDMI_I2C_TRANSACTION_REG_START; 162 163 if (i == (num - 1)) 164 i2c_trans |= HDMI_I2C_TRANSACTION_REG_STOP; 165 166 hdmi_write(hdmi, REG_HDMI_I2C_TRANSACTION(i), i2c_trans); 167 } 168 169 /* trigger the transfer: */ 170 hdmi_write(hdmi, REG_HDMI_DDC_CTRL, 171 HDMI_DDC_CTRL_TRANSACTION_CNT(num - 1) | 172 HDMI_DDC_CTRL_GO); 173 174 ret = wait_event_timeout(hdmi_i2c->ddc_event, sw_done(hdmi_i2c), HZ/4); 175 if (ret <= 0) { 176 if (ret == 0) 177 ret = -ETIMEDOUT; 178 dev_warn(dev->dev, "DDC timeout: %d\n", ret); 179 DBG("sw_status=%08x, hw_status=%08x, int_ctrl=%08x", 180 hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS), 181 hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS), 182 hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL)); 183 return ret; 184 } 185 186 ddc_status = hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS); 187 188 /* read back results of any read transactions: */ 189 for (i = 0; i < num; i++) { 190 struct i2c_msg *p = &msgs[i]; 191 192 if (!(p->flags & I2C_M_RD)) 193 continue; 194 195 /* check for NACK: */ 196 if (ddc_status & nack[i]) { 197 DBG("ddc_status=%08x", ddc_status); 198 break; 199 } 200 201 ddc_data = HDMI_DDC_DATA_DATA_RW(DDC_READ) | 202 HDMI_DDC_DATA_INDEX(indices[i]) | 203 HDMI_DDC_DATA_INDEX_WRITE; 204 205 hdmi_write(hdmi, REG_HDMI_DDC_DATA, ddc_data); 206 207 /* discard first byte: */ 208 hdmi_read(hdmi, REG_HDMI_DDC_DATA); 209 210 for (j = 0; j < p->len; j++) { 211 ddc_data = hdmi_read(hdmi, REG_HDMI_DDC_DATA); 212 p->buf[j] = FIELD(ddc_data, HDMI_DDC_DATA_DATA); 213 } 214 } 215 216 return i; 217} 218 219static u32 hdmi_i2c_func(struct i2c_adapter *adapter) 220{ 221 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 222} 223 224static const struct i2c_algorithm hdmi_i2c_algorithm = { 225 .master_xfer = hdmi_i2c_xfer, 226 .functionality = hdmi_i2c_func, 227}; 228 229void hdmi_i2c_irq(struct i2c_adapter *i2c) 230{ 231 struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(i2c); 232 233 if (sw_done(hdmi_i2c)) 234 wake_up_all(&hdmi_i2c->ddc_event); 235} 236 237void hdmi_i2c_destroy(struct i2c_adapter *i2c) 238{ 239 struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(i2c); 240 i2c_del_adapter(i2c); 241 kfree(hdmi_i2c); 242} 243 244struct i2c_adapter *hdmi_i2c_init(struct hdmi *hdmi) 245{ 246 struct drm_device *dev = hdmi->dev; 247 struct hdmi_i2c_adapter *hdmi_i2c; 248 struct i2c_adapter *i2c = NULL; 249 int ret; 250 251 hdmi_i2c = kzalloc(sizeof(*hdmi_i2c), GFP_KERNEL); 252 if (!hdmi_i2c) { 253 ret = -ENOMEM; 254 goto fail; 255 } 256 257 i2c = &hdmi_i2c->base; 258 259 hdmi_i2c->hdmi = hdmi; 260 init_waitqueue_head(&hdmi_i2c->ddc_event); 261 262 263 i2c->owner = THIS_MODULE; 264 i2c->class = I2C_CLASS_DDC; 265 snprintf(i2c->name, sizeof(i2c->name), "msm hdmi i2c"); 266 i2c->dev.parent = &hdmi->pdev->dev; 267 i2c->algo = &hdmi_i2c_algorithm; 268 269 ret = i2c_add_adapter(i2c); 270 if (ret) { 271 dev_err(dev->dev, "failed to register hdmi i2c: %d\n", ret); 272 goto fail; 273 } 274 275 return i2c; 276 277fail: 278 if (i2c) 279 hdmi_i2c_destroy(i2c); 280 return ERR_PTR(ret); 281} 282