anx9805.c revision c865534f1e5b5b4ef03f4a55cf4730f4b70dd75b
1/* 2 * Copyright 2013 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs <bskeggs@redhat.com> 23 */ 24 25#include <subdev/i2c.h> 26 27struct anx9805_i2c_port { 28 struct nouveau_i2c_port base; 29 u32 addr; 30 u32 ctrl; 31}; 32 33static int 34anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) 35{ 36 struct anx9805_i2c_port *chan = (void *)port; 37 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; 38 u8 tmp, i; 39 40 nv_wri2cr(mast, chan->addr, 0xa0, link_bw); 41 nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); 42 nv_wri2cr(mast, chan->addr, 0xa2, 0x01); 43 nv_wri2cr(mast, chan->addr, 0xa8, 0x01); 44 45 i = 0; 46 while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) { 47 mdelay(5); 48 if (i++ == 100) { 49 nv_error(port, "link training timed out\n"); 50 return -ETIMEDOUT; 51 } 52 } 53 54 if (tmp & 0x70) { 55 nv_error(port, "link training failed: 0x%02x\n", tmp); 56 return -EIO; 57 } 58 59 return 1; 60} 61 62static int 63anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) 64{ 65 struct anx9805_i2c_port *chan = (void *)port; 66 struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; 67 int i, ret = -ETIMEDOUT; 68 u8 tmp; 69 70 tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; 71 nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); 72 nv_wri2cr(mast, chan->ctrl, 0x07, tmp); 73 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); 74 75 nv_wri2cr(mast, chan->addr, 0xe4, 0x80); 76 for (i = 0; !(type & 1) && i < size; i++) 77 nv_wri2cr(mast, chan->addr, 0xf0 + i, data[i]); 78 nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); 79 nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); 80 nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); 81 nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16); 82 nv_wri2cr(mast, chan->addr, 0xe9, 0x01); 83 84 i = 0; 85 while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) { 86 mdelay(5); 87 if (i++ == 32) 88 goto done; 89 } 90 91 if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) { 92 ret = -EIO; 93 goto done; 94 } 95 96 for (i = 0; (type & 1) && i < size; i++) 97 data[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); 98 ret = 0; 99done: 100 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); 101 return ret; 102} 103 104static const struct nouveau_i2c_func 105anx9805_aux_func = { 106 .aux = anx9805_aux, 107 .lnk_ctl = anx9805_train, 108}; 109 110static int 111anx9805_aux_chan_ctor(struct nouveau_object *parent, 112 struct nouveau_object *engine, 113 struct nouveau_oclass *oclass, void *data, u32 index, 114 struct nouveau_object **pobject) 115{ 116 struct nouveau_i2c_port *mast = (void *)parent; 117 struct anx9805_i2c_port *chan; 118 int ret; 119 120 ret = nouveau_i2c_port_create(parent, engine, oclass, index, 121 &nouveau_i2c_aux_algo, &anx9805_aux_func, 122 &chan); 123 *pobject = nv_object(chan); 124 if (ret) 125 return ret; 126 127 switch ((oclass->handle & 0xff00) >> 8) { 128 case 0x0d: 129 chan->addr = 0x38; 130 chan->ctrl = 0x39; 131 break; 132 case 0x0e: 133 chan->addr = 0x3c; 134 chan->ctrl = 0x3b; 135 break; 136 default: 137 BUG_ON(1); 138 } 139 140 if (mast->adapter.algo == &i2c_bit_algo) { 141 struct i2c_algo_bit_data *algo = mast->adapter.algo_data; 142 algo->udelay = max(algo->udelay, 40); 143 } 144 return 0; 145} 146 147static struct nouveau_ofuncs 148anx9805_aux_ofuncs = { 149 .ctor = anx9805_aux_chan_ctor, 150 .dtor = _nouveau_i2c_port_dtor, 151 .init = _nouveau_i2c_port_init, 152 .fini = _nouveau_i2c_port_fini, 153}; 154 155static int 156anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 157{ 158 struct anx9805_i2c_port *port = adap->algo_data; 159 struct nouveau_i2c_port *mast = (void *)nv_object(port)->parent; 160 struct i2c_msg *msg = msgs; 161 int ret = -ETIMEDOUT; 162 int i, j, cnt = num; 163 u8 seg = 0x00, off = 0x00, tmp; 164 165 tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10; 166 nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10); 167 nv_wri2cr(mast, port->ctrl, 0x07, tmp); 168 nv_wri2cr(mast, port->addr, 0x43, 0x05); 169 mdelay(5); 170 171 while (cnt--) { 172 if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) { 173 nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1); 174 nv_wri2cr(mast, port->addr, 0x41, seg); 175 nv_wri2cr(mast, port->addr, 0x42, off); 176 nv_wri2cr(mast, port->addr, 0x44, msg->len); 177 nv_wri2cr(mast, port->addr, 0x45, 0x00); 178 nv_wri2cr(mast, port->addr, 0x43, 0x01); 179 for (i = 0; i < msg->len; i++) { 180 j = 0; 181 while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) { 182 mdelay(5); 183 if (j++ == 32) 184 goto done; 185 } 186 msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47); 187 } 188 } else 189 if (!(msg->flags & I2C_M_RD)) { 190 if (msg->addr == 0x50 && msg->len == 0x01) { 191 off = msg->buf[0]; 192 } else 193 if (msg->addr == 0x30 && msg->len == 0x01) { 194 seg = msg->buf[0]; 195 } else 196 goto done; 197 } else { 198 goto done; 199 } 200 msg++; 201 } 202 203 ret = num; 204done: 205 nv_wri2cr(mast, port->addr, 0x43, 0x00); 206 return ret; 207} 208 209static u32 210anx9805_func(struct i2c_adapter *adap) 211{ 212 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 213} 214 215static const struct i2c_algorithm 216anx9805_i2c_algo = { 217 .master_xfer = anx9805_xfer, 218 .functionality = anx9805_func 219}; 220 221static const struct nouveau_i2c_func 222anx9805_i2c_func = { 223}; 224 225static int 226anx9805_ddc_port_ctor(struct nouveau_object *parent, 227 struct nouveau_object *engine, 228 struct nouveau_oclass *oclass, void *data, u32 index, 229 struct nouveau_object **pobject) 230{ 231 struct nouveau_i2c_port *mast = (void *)parent; 232 struct anx9805_i2c_port *port; 233 int ret; 234 235 ret = nouveau_i2c_port_create(parent, engine, oclass, index, 236 &anx9805_i2c_algo, &anx9805_i2c_func, 237 &port); 238 *pobject = nv_object(port); 239 if (ret) 240 return ret; 241 242 switch ((oclass->handle & 0xff00) >> 8) { 243 case 0x0d: 244 port->addr = 0x3d; 245 port->ctrl = 0x39; 246 break; 247 case 0x0e: 248 port->addr = 0x3f; 249 port->ctrl = 0x3b; 250 break; 251 default: 252 BUG_ON(1); 253 } 254 255 if (mast->adapter.algo == &i2c_bit_algo) { 256 struct i2c_algo_bit_data *algo = mast->adapter.algo_data; 257 algo->udelay = max(algo->udelay, 40); 258 } 259 return 0; 260} 261 262static struct nouveau_ofuncs 263anx9805_ddc_ofuncs = { 264 .ctor = anx9805_ddc_port_ctor, 265 .dtor = _nouveau_i2c_port_dtor, 266 .init = _nouveau_i2c_port_init, 267 .fini = _nouveau_i2c_port_fini, 268}; 269 270struct nouveau_oclass 271nouveau_anx9805_sclass[] = { 272 { .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs }, 273 { .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs }, 274 { .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs }, 275 { .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs }, 276 {} 277}; 278