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 #include "port.h" 25 26 struct anx9805_i2c_port { 27 struct nvkm_i2c_port base; 28 u32 addr; 29 u32 ctrl; 30 }; 31 32 static int 33 anx9805_train(struct nvkm_i2c_port *port, int link_nr, int link_bw, bool enh) 34 { 35 struct nvkm_i2c *i2c = nvkm_i2c(port); 36 struct nvkm_subdev *subdev = &i2c->subdev; 37 struct anx9805_i2c_port *chan = (void *)port; 38 struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent; 39 u8 tmp, i; 40 41 DBG("ANX9805 train %d %02x %d\n", link_nr, link_bw, enh); 42 43 nv_wri2cr(mast, chan->addr, 0xa0, link_bw); 44 nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); 45 nv_wri2cr(mast, chan->addr, 0xa2, 0x01); 46 nv_wri2cr(mast, chan->addr, 0xa8, 0x01); 47 48 i = 0; 49 while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) { 50 mdelay(5); 51 if (i++ == 100) { 52 nvkm_error(subdev, "link training timed out\n"); 53 return -ETIMEDOUT; 54 } 55 } 56 57 if (tmp & 0x70) { 58 nvkm_error(subdev, "link training failed: %02x\n", tmp); 59 return -EIO; 60 } 61 62 return 1; 63 } 64 65 static int 66 anx9805_aux(struct nvkm_i2c_port *port, bool retry, 67 u8 type, u32 addr, u8 *data, u8 size) 68 { 69 struct anx9805_i2c_port *chan = (void *)port; 70 struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent; 71 int i, ret = -ETIMEDOUT; 72 u8 buf[16] = {}; 73 u8 tmp; 74 75 DBG("%02x %05x %d\n", type, addr, size); 76 77 tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; 78 nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); 79 nv_wri2cr(mast, chan->ctrl, 0x07, tmp); 80 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); 81 82 nv_wri2cr(mast, chan->addr, 0xe4, 0x80); 83 if (!(type & 1)) { 84 memcpy(buf, data, size); 85 DBG("%16ph", buf); 86 for (i = 0; i < size; i++) 87 nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]); 88 } 89 nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); 90 nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); 91 nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); 92 nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16); 93 nv_wri2cr(mast, chan->addr, 0xe9, 0x01); 94 95 i = 0; 96 while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) { 97 mdelay(5); 98 if (i++ == 32) 99 goto done; 100 } 101 102 if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) { 103 ret = -EIO; 104 goto done; 105 } 106 107 if (type & 1) { 108 for (i = 0; i < size; i++) 109 buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); 110 DBG("%16ph", buf); 111 memcpy(data, buf, size); 112 } 113 114 ret = 0; 115 done: 116 nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); 117 return ret; 118 } 119 120 static const struct nvkm_i2c_func 121 anx9805_aux_func = { 122 .aux = anx9805_aux, 123 .lnk_ctl = anx9805_train, 124 }; 125 126 static int 127 anx9805_aux_chan_ctor(struct nvkm_object *parent, 128 struct nvkm_object *engine, 129 struct nvkm_oclass *oclass, void *data, u32 index, 130 struct nvkm_object **pobject) 131 { 132 struct nvkm_i2c_port *mast = (void *)parent; 133 struct anx9805_i2c_port *chan; 134 int ret; 135 136 ret = nvkm_i2c_port_create(parent, engine, oclass, index, 137 &nvkm_i2c_aux_algo, &anx9805_aux_func, 138 &chan); 139 *pobject = nv_object(chan); 140 if (ret) 141 return ret; 142 143 switch ((oclass->handle & 0xff00) >> 8) { 144 case 0x0d: 145 chan->addr = 0x38; 146 chan->ctrl = 0x39; 147 break; 148 case 0x0e: 149 chan->addr = 0x3c; 150 chan->ctrl = 0x3b; 151 break; 152 default: 153 BUG_ON(1); 154 } 155 156 if (mast->adapter.algo == &i2c_bit_algo) { 157 struct i2c_algo_bit_data *algo = mast->adapter.algo_data; 158 algo->udelay = max(algo->udelay, 40); 159 } 160 161 return 0; 162 } 163 164 static struct nvkm_ofuncs 165 anx9805_aux_ofuncs = { 166 .ctor = anx9805_aux_chan_ctor, 167 .dtor = _nvkm_i2c_port_dtor, 168 .init = _nvkm_i2c_port_init, 169 .fini = _nvkm_i2c_port_fini, 170 }; 171 172 static int 173 anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 174 { 175 struct anx9805_i2c_port *port = adap->algo_data; 176 struct nvkm_i2c_port *mast = (void *)nv_object(port)->parent; 177 struct i2c_msg *msg = msgs; 178 int ret = -ETIMEDOUT; 179 int i, j, cnt = num; 180 u8 seg = 0x00, off = 0x00, tmp; 181 182 tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10; 183 nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10); 184 nv_wri2cr(mast, port->ctrl, 0x07, tmp); 185 nv_wri2cr(mast, port->addr, 0x43, 0x05); 186 mdelay(5); 187 188 while (cnt--) { 189 if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) { 190 nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1); 191 nv_wri2cr(mast, port->addr, 0x41, seg); 192 nv_wri2cr(mast, port->addr, 0x42, off); 193 nv_wri2cr(mast, port->addr, 0x44, msg->len); 194 nv_wri2cr(mast, port->addr, 0x45, 0x00); 195 nv_wri2cr(mast, port->addr, 0x43, 0x01); 196 for (i = 0; i < msg->len; i++) { 197 j = 0; 198 while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) { 199 mdelay(5); 200 if (j++ == 32) 201 goto done; 202 } 203 msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47); 204 } 205 } else 206 if (!(msg->flags & I2C_M_RD)) { 207 if (msg->addr == 0x50 && msg->len == 0x01) { 208 off = msg->buf[0]; 209 } else 210 if (msg->addr == 0x30 && msg->len == 0x01) { 211 seg = msg->buf[0]; 212 } else 213 goto done; 214 } else { 215 goto done; 216 } 217 msg++; 218 } 219 220 ret = num; 221 done: 222 nv_wri2cr(mast, port->addr, 0x43, 0x00); 223 return ret; 224 } 225 226 static u32 227 anx9805_func(struct i2c_adapter *adap) 228 { 229 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 230 } 231 232 static const struct i2c_algorithm 233 anx9805_i2c_algo = { 234 .master_xfer = anx9805_xfer, 235 .functionality = anx9805_func 236 }; 237 238 static const struct nvkm_i2c_func 239 anx9805_i2c_func = { 240 }; 241 242 static int 243 anx9805_ddc_port_ctor(struct nvkm_object *parent, 244 struct nvkm_object *engine, 245 struct nvkm_oclass *oclass, void *data, u32 index, 246 struct nvkm_object **pobject) 247 { 248 struct nvkm_i2c_port *mast = (void *)parent; 249 struct anx9805_i2c_port *port; 250 int ret; 251 252 ret = nvkm_i2c_port_create(parent, engine, oclass, index, 253 &anx9805_i2c_algo, &anx9805_i2c_func, &port); 254 *pobject = nv_object(port); 255 if (ret) 256 return ret; 257 258 switch ((oclass->handle & 0xff00) >> 8) { 259 case 0x0d: 260 port->addr = 0x3d; 261 port->ctrl = 0x39; 262 break; 263 case 0x0e: 264 port->addr = 0x3f; 265 port->ctrl = 0x3b; 266 break; 267 default: 268 BUG_ON(1); 269 } 270 271 if (mast->adapter.algo == &i2c_bit_algo) { 272 struct i2c_algo_bit_data *algo = mast->adapter.algo_data; 273 algo->udelay = max(algo->udelay, 40); 274 } 275 276 return 0; 277 } 278 279 static struct nvkm_ofuncs 280 anx9805_ddc_ofuncs = { 281 .ctor = anx9805_ddc_port_ctor, 282 .dtor = _nvkm_i2c_port_dtor, 283 .init = _nvkm_i2c_port_init, 284 .fini = _nvkm_i2c_port_fini, 285 }; 286 287 struct nvkm_oclass 288 nvkm_anx9805_sclass[] = { 289 { .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs }, 290 { .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs }, 291 { .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs }, 292 { .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs }, 293 {} 294 }; 295