1/* 2 * Copyright © 2009 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include <linux/kernel.h> 24#include <linux/module.h> 25#include <linux/delay.h> 26#include <linux/init.h> 27#include <linux/errno.h> 28#include <linux/sched.h> 29#include <linux/i2c.h> 30#include "drm_dp_helper.h" 31#include "drmP.h" 32 33/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ 34static int 35i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode, 36 uint8_t write_byte, uint8_t *read_byte) 37{ 38 struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; 39 int ret; 40 41 ret = (*algo_data->aux_ch)(adapter, mode, 42 write_byte, read_byte); 43 return ret; 44} 45 46/* 47 * I2C over AUX CH 48 */ 49 50/* 51 * Send the address. If the I2C link is running, this 'restarts' 52 * the connection with the new address, this is used for doing 53 * a write followed by a read (as needed for DDC) 54 */ 55static int 56i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) 57{ 58 struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; 59 int mode = MODE_I2C_START; 60 int ret; 61 62 if (reading) 63 mode |= MODE_I2C_READ; 64 else 65 mode |= MODE_I2C_WRITE; 66 algo_data->address = address; 67 algo_data->running = true; 68 ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); 69 return ret; 70} 71 72/* 73 * Stop the I2C transaction. This closes out the link, sending 74 * a bare address packet with the MOT bit turned off 75 */ 76static void 77i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading) 78{ 79 struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; 80 int mode = MODE_I2C_STOP; 81 82 if (reading) 83 mode |= MODE_I2C_READ; 84 else 85 mode |= MODE_I2C_WRITE; 86 if (algo_data->running) { 87 (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); 88 algo_data->running = false; 89 } 90} 91 92/* 93 * Write a single byte to the current I2C address, the 94 * the I2C link must be running or this returns -EIO 95 */ 96static int 97i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) 98{ 99 struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; 100 int ret; 101 102 if (!algo_data->running) 103 return -EIO; 104 105 ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); 106 return ret; 107} 108 109/* 110 * Read a single byte from the current I2C address, the 111 * I2C link must be running or this returns -EIO 112 */ 113static int 114i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) 115{ 116 struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; 117 int ret; 118 119 if (!algo_data->running) 120 return -EIO; 121 122 ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); 123 return ret; 124} 125 126static int 127i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter, 128 struct i2c_msg *msgs, 129 int num) 130{ 131 int ret = 0; 132 bool reading = false; 133 int m; 134 int b; 135 136 for (m = 0; m < num; m++) { 137 u16 len = msgs[m].len; 138 u8 *buf = msgs[m].buf; 139 reading = (msgs[m].flags & I2C_M_RD) != 0; 140 ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading); 141 if (ret < 0) 142 break; 143 if (reading) { 144 for (b = 0; b < len; b++) { 145 ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]); 146 if (ret < 0) 147 break; 148 } 149 } else { 150 for (b = 0; b < len; b++) { 151 ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]); 152 if (ret < 0) 153 break; 154 } 155 } 156 if (ret < 0) 157 break; 158 } 159 if (ret >= 0) 160 ret = num; 161 i2c_algo_dp_aux_stop(adapter, reading); 162 DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret); 163 return ret; 164} 165 166static u32 167i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter) 168{ 169 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 170 I2C_FUNC_SMBUS_READ_BLOCK_DATA | 171 I2C_FUNC_SMBUS_BLOCK_PROC_CALL | 172 I2C_FUNC_10BIT_ADDR; 173} 174 175static const struct i2c_algorithm i2c_dp_aux_algo = { 176 .master_xfer = i2c_algo_dp_aux_xfer, 177 .functionality = i2c_algo_dp_aux_functionality, 178}; 179 180static void 181i2c_dp_aux_reset_bus(struct i2c_adapter *adapter) 182{ 183 (void) i2c_algo_dp_aux_address(adapter, 0, false); 184 (void) i2c_algo_dp_aux_stop(adapter, false); 185 186} 187 188static int 189i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter) 190{ 191 adapter->algo = &i2c_dp_aux_algo; 192 adapter->retries = 3; 193 i2c_dp_aux_reset_bus(adapter); 194 return 0; 195} 196 197int 198i2c_dp_aux_add_bus(struct i2c_adapter *adapter) 199{ 200 int error; 201 202 error = i2c_dp_aux_prepare_bus(adapter); 203 if (error) 204 return error; 205 error = i2c_add_adapter(adapter); 206 return error; 207} 208EXPORT_SYMBOL(i2c_dp_aux_add_bus); 209