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