Home | History | Annotate | Line # | Download | only in i2c
      1 /*	$NetBSD: nouveau_nvkm_subdev_i2c_anx9805.c,v 1.3 2021/12/18 23:45:40 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2013 Red Hat Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Ben Skeggs <bskeggs (at) redhat.com>
     25  */
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_i2c_anx9805.c,v 1.3 2021/12/18 23:45:40 riastradh Exp $");
     28 
     29 #define anx9805_pad(p) container_of((p), struct anx9805_pad, base)
     30 #define anx9805_bus(p) container_of((p), struct anx9805_bus, base)
     31 #define anx9805_aux(p) container_of((p), struct anx9805_aux, base)
     32 #include "aux.h"
     33 #include "bus.h"
     34 
     35 struct anx9805_pad {
     36 	struct nvkm_i2c_pad base;
     37 	struct nvkm_i2c_bus *bus;
     38 	u8 addr;
     39 };
     40 
     41 struct anx9805_bus {
     42 	struct nvkm_i2c_bus base;
     43 	struct anx9805_pad *pad;
     44 	u8 addr;
     45 };
     46 
     47 static int
     48 anx9805_bus_xfer(struct nvkm_i2c_bus *base, struct i2c_msg *msgs, int num)
     49 {
     50 	struct anx9805_bus *bus = anx9805_bus(base);
     51 	struct anx9805_pad *pad = bus->pad;
     52 	struct i2c_adapter *adap = &pad->bus->i2c;
     53 	struct i2c_msg *msg = msgs;
     54 	int ret = -ETIMEDOUT;
     55 	int i, j, cnt = num;
     56 	u8 seg = 0x00, off = 0x00, tmp;
     57 
     58 	tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x10;
     59 	nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x10);
     60 	nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
     61 	nvkm_wri2cr(adap, bus->addr, 0x43, 0x05);
     62 	mdelay(5);
     63 
     64 	while (cnt--) {
     65 		if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
     66 			nvkm_wri2cr(adap, bus->addr, 0x40, msg->addr << 1);
     67 			nvkm_wri2cr(adap, bus->addr, 0x41, seg);
     68 			nvkm_wri2cr(adap, bus->addr, 0x42, off);
     69 			nvkm_wri2cr(adap, bus->addr, 0x44, msg->len);
     70 			nvkm_wri2cr(adap, bus->addr, 0x45, 0x00);
     71 			nvkm_wri2cr(adap, bus->addr, 0x43, 0x01);
     72 			for (i = 0; i < msg->len; i++) {
     73 				j = 0;
     74 				while (nvkm_rdi2cr(adap, bus->addr, 0x46) & 0x10) {
     75 					mdelay(5);
     76 					if (j++ == 32)
     77 						goto done;
     78 				}
     79 				msg->buf[i] = nvkm_rdi2cr(adap, bus->addr, 0x47);
     80 			}
     81 		} else
     82 		if (!(msg->flags & I2C_M_RD)) {
     83 			if (msg->addr == 0x50 && msg->len == 0x01) {
     84 				off = msg->buf[0];
     85 			} else
     86 			if (msg->addr == 0x30 && msg->len == 0x01) {
     87 				seg = msg->buf[0];
     88 			} else
     89 				goto done;
     90 		} else {
     91 			goto done;
     92 		}
     93 		msg++;
     94 	}
     95 
     96 	ret = num;
     97 done:
     98 	nvkm_wri2cr(adap, bus->addr, 0x43, 0x00);
     99 	return ret;
    100 }
    101 
    102 static const struct nvkm_i2c_bus_func
    103 anx9805_bus_func = {
    104 	.xfer = anx9805_bus_xfer,
    105 };
    106 
    107 static int
    108 anx9805_bus_new(struct nvkm_i2c_pad *base, int id, u8 drive,
    109 		struct nvkm_i2c_bus **pbus)
    110 {
    111 	struct anx9805_pad *pad = anx9805_pad(base);
    112 	struct anx9805_bus *bus;
    113 	int ret;
    114 
    115 	if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL)))
    116 		return -ENOMEM;
    117 	*pbus = &bus->base;
    118 	bus->pad = pad;
    119 
    120 	ret = nvkm_i2c_bus_ctor(&anx9805_bus_func, &pad->base, id, &bus->base);
    121 	if (ret)
    122 		return ret;
    123 
    124 	switch (pad->addr) {
    125 	case 0x39: bus->addr = 0x3d; break;
    126 	case 0x3b: bus->addr = 0x3f; break;
    127 	default:
    128 		return -ENOSYS;
    129 	}
    130 
    131 	return 0;
    132 }
    133 
    134 struct anx9805_aux {
    135 	struct nvkm_i2c_aux base;
    136 	struct anx9805_pad *pad;
    137 	u8 addr;
    138 };
    139 
    140 static int
    141 anx9805_aux_xfer(struct nvkm_i2c_aux *base, bool retry,
    142 		 u8 type, u32 addr, u8 *data, u8 *size)
    143 {
    144 	struct anx9805_aux *aux = anx9805_aux(base);
    145 	struct anx9805_pad *pad = aux->pad;
    146 	struct i2c_adapter *adap = &pad->bus->i2c;
    147 	int i, ret = -ETIMEDOUT;
    148 	u8 buf[16] = {};
    149 	u8 tmp;
    150 
    151 	AUX_DBG(&aux->base, "%02x %05x %d", type, addr, *size);
    152 
    153 	tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x04;
    154 	nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x04);
    155 	nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
    156 	nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
    157 
    158 	nvkm_wri2cr(adap, aux->addr, 0xe4, 0x80);
    159 	if (!(type & 1)) {
    160 		memcpy(buf, data, *size);
    161 		AUX_DBG(&aux->base, "%16ph", buf);
    162 		for (i = 0; i < *size; i++)
    163 			nvkm_wri2cr(adap, aux->addr, 0xf0 + i, buf[i]);
    164 	}
    165 	nvkm_wri2cr(adap, aux->addr, 0xe5, ((*size - 1) << 4) | type);
    166 	nvkm_wri2cr(adap, aux->addr, 0xe6, (addr & 0x000ff) >>  0);
    167 	nvkm_wri2cr(adap, aux->addr, 0xe7, (addr & 0x0ff00) >>  8);
    168 	nvkm_wri2cr(adap, aux->addr, 0xe8, (addr & 0xf0000) >> 16);
    169 	nvkm_wri2cr(adap, aux->addr, 0xe9, 0x01);
    170 
    171 	i = 0;
    172 	while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xe9)) & 0x01) {
    173 		mdelay(5);
    174 		if (i++ == 32)
    175 			goto done;
    176 	}
    177 
    178 	if ((tmp = nvkm_rdi2cr(adap, pad->addr, 0xf7)) & 0x01) {
    179 		ret = -EIO;
    180 		goto done;
    181 	}
    182 
    183 	if (type & 1) {
    184 		for (i = 0; i < *size; i++)
    185 			buf[i] = nvkm_rdi2cr(adap, aux->addr, 0xf0 + i);
    186 		AUX_DBG(&aux->base, "%16ph", buf);
    187 		memcpy(data, buf, *size);
    188 	}
    189 
    190 	ret = 0;
    191 done:
    192 	nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
    193 	return ret;
    194 }
    195 
    196 static int
    197 anx9805_aux_lnk_ctl(struct nvkm_i2c_aux *base,
    198 		    int link_nr, int link_bw, bool enh)
    199 {
    200 	struct anx9805_aux *aux = anx9805_aux(base);
    201 	struct anx9805_pad *pad = aux->pad;
    202 	struct i2c_adapter *adap = &pad->bus->i2c;
    203 	u8 tmp, i;
    204 
    205 	AUX_DBG(&aux->base, "ANX9805 train %d %02x %d",
    206 		link_nr, link_bw, enh);
    207 
    208 	nvkm_wri2cr(adap, aux->addr, 0xa0, link_bw);
    209 	nvkm_wri2cr(adap, aux->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
    210 	nvkm_wri2cr(adap, aux->addr, 0xa2, 0x01);
    211 	nvkm_wri2cr(adap, aux->addr, 0xa8, 0x01);
    212 
    213 	i = 0;
    214 	while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xa8)) & 0x01) {
    215 		mdelay(5);
    216 		if (i++ == 100) {
    217 			AUX_ERR(&aux->base, "link training timeout");
    218 			return -ETIMEDOUT;
    219 		}
    220 	}
    221 
    222 	if (tmp & 0x70) {
    223 		AUX_ERR(&aux->base, "link training failed");
    224 		return -EIO;
    225 	}
    226 
    227 	return 0;
    228 }
    229 
    230 static const struct nvkm_i2c_aux_func
    231 anx9805_aux_func = {
    232 	.xfer = anx9805_aux_xfer,
    233 	.lnk_ctl = anx9805_aux_lnk_ctl,
    234 };
    235 
    236 static int
    237 anx9805_aux_new(struct nvkm_i2c_pad *base, int id, u8 drive,
    238 		struct nvkm_i2c_aux **pbus)
    239 {
    240 	struct anx9805_pad *pad = anx9805_pad(base);
    241 	struct anx9805_aux *aux;
    242 	int ret;
    243 
    244 	if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL)))
    245 		return -ENOMEM;
    246 	*pbus = &aux->base;
    247 	aux->pad = pad;
    248 
    249 	ret = nvkm_i2c_aux_ctor(&anx9805_aux_func, &pad->base, id, &aux->base);
    250 	if (ret)
    251 		return ret;
    252 
    253 	switch (pad->addr) {
    254 	case 0x39: aux->addr = 0x38; break;
    255 	case 0x3b: aux->addr = 0x3c; break;
    256 	default:
    257 		return -ENOSYS;
    258 	}
    259 
    260 	return 0;
    261 }
    262 
    263 static const struct nvkm_i2c_pad_func
    264 anx9805_pad_func = {
    265 	.bus_new_4 = anx9805_bus_new,
    266 	.aux_new_6 = anx9805_aux_new,
    267 };
    268 
    269 int
    270 anx9805_pad_new(struct nvkm_i2c_bus *bus, int id, u8 addr,
    271 		struct nvkm_i2c_pad **ppad)
    272 {
    273 	struct anx9805_pad *pad;
    274 
    275 	if (!(pad = kzalloc(sizeof(*pad), GFP_KERNEL)))
    276 		return -ENOMEM;
    277 	*ppad = &pad->base;
    278 
    279 	nvkm_i2c_pad_ctor(&anx9805_pad_func, bus->pad->i2c, id, &pad->base);
    280 	pad->bus = bus;
    281 	pad->addr = addr;
    282 	return 0;
    283 }
    284