xref: /linux/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxch.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
1*231bb9b4SBenjamin Szőke /*
2*231bb9b4SBenjamin Szőke  * Copyright 2009 Red Hat Inc.
3*231bb9b4SBenjamin Szőke  *
4*231bb9b4SBenjamin Szőke  * Permission is hereby granted, free of charge, to any person obtaining a
5*231bb9b4SBenjamin Szőke  * copy of this software and associated documentation files (the "Software"),
6*231bb9b4SBenjamin Szőke  * to deal in the Software without restriction, including without limitation
7*231bb9b4SBenjamin Szőke  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*231bb9b4SBenjamin Szőke  * and/or sell copies of the Software, and to permit persons to whom the
9*231bb9b4SBenjamin Szőke  * Software is furnished to do so, subject to the following conditions:
10*231bb9b4SBenjamin Szőke  *
11*231bb9b4SBenjamin Szőke  * The above copyright notice and this permission notice shall be included in
12*231bb9b4SBenjamin Szőke  * all copies or substantial portions of the Software.
13*231bb9b4SBenjamin Szőke  *
14*231bb9b4SBenjamin Szőke  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*231bb9b4SBenjamin Szőke  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*231bb9b4SBenjamin Szőke  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*231bb9b4SBenjamin Szőke  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*231bb9b4SBenjamin Szőke  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*231bb9b4SBenjamin Szőke  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*231bb9b4SBenjamin Szőke  * OTHER DEALINGS IN THE SOFTWARE.
21*231bb9b4SBenjamin Szőke  *
22*231bb9b4SBenjamin Szőke  * Authors: Ben Skeggs
23*231bb9b4SBenjamin Szőke  */
24*231bb9b4SBenjamin Szőke 
25*231bb9b4SBenjamin Szőke #include <linux/string_helpers.h>
26*231bb9b4SBenjamin Szőke 
27*231bb9b4SBenjamin Szőke #include "auxch.h"
28*231bb9b4SBenjamin Szőke #include "pad.h"
29*231bb9b4SBenjamin Szőke 
30*231bb9b4SBenjamin Szőke static int
31*231bb9b4SBenjamin Szőke nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
32*231bb9b4SBenjamin Szőke {
33*231bb9b4SBenjamin Szőke 	struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c);
34*231bb9b4SBenjamin Szőke 	struct i2c_msg *msg = msgs;
35*231bb9b4SBenjamin Szőke 	int ret, mcnt = num;
36*231bb9b4SBenjamin Szőke 
37*231bb9b4SBenjamin Szőke 	ret = nvkm_i2c_aux_acquire(aux);
38*231bb9b4SBenjamin Szőke 	if (ret)
39*231bb9b4SBenjamin Szőke 		return ret;
40*231bb9b4SBenjamin Szőke 
41*231bb9b4SBenjamin Szőke 	while (mcnt--) {
42*231bb9b4SBenjamin Szőke 		u8 remaining = msg->len;
43*231bb9b4SBenjamin Szőke 		u8 *ptr = msg->buf;
44*231bb9b4SBenjamin Szőke 
45*231bb9b4SBenjamin Szőke 		while (remaining) {
46*231bb9b4SBenjamin Szőke 			u8 cnt, retries, cmd;
47*231bb9b4SBenjamin Szőke 
48*231bb9b4SBenjamin Szőke 			if (msg->flags & I2C_M_RD)
49*231bb9b4SBenjamin Szőke 				cmd = 1;
50*231bb9b4SBenjamin Szőke 			else
51*231bb9b4SBenjamin Szőke 				cmd = 0;
52*231bb9b4SBenjamin Szőke 
53*231bb9b4SBenjamin Szőke 			if (mcnt || remaining > 16)
54*231bb9b4SBenjamin Szőke 				cmd |= 4; /* MOT */
55*231bb9b4SBenjamin Szőke 
56*231bb9b4SBenjamin Szőke 			for (retries = 0, cnt = 0;
57*231bb9b4SBenjamin Szőke 			     retries < 32 && !cnt;
58*231bb9b4SBenjamin Szőke 			     retries++) {
59*231bb9b4SBenjamin Szőke 				cnt = min_t(u8, remaining, 16);
60*231bb9b4SBenjamin Szőke 				ret = aux->func->xfer(aux, true, cmd,
61*231bb9b4SBenjamin Szőke 						      msg->addr, ptr, &cnt);
62*231bb9b4SBenjamin Szőke 				if (ret < 0)
63*231bb9b4SBenjamin Szőke 					goto out;
64*231bb9b4SBenjamin Szőke 			}
65*231bb9b4SBenjamin Szőke 			if (!cnt) {
66*231bb9b4SBenjamin Szőke 				AUX_TRACE(aux, "no data after 32 retries");
67*231bb9b4SBenjamin Szőke 				ret = -EIO;
68*231bb9b4SBenjamin Szőke 				goto out;
69*231bb9b4SBenjamin Szőke 			}
70*231bb9b4SBenjamin Szőke 
71*231bb9b4SBenjamin Szőke 			ptr += cnt;
72*231bb9b4SBenjamin Szőke 			remaining -= cnt;
73*231bb9b4SBenjamin Szőke 		}
74*231bb9b4SBenjamin Szőke 
75*231bb9b4SBenjamin Szőke 		msg++;
76*231bb9b4SBenjamin Szőke 	}
77*231bb9b4SBenjamin Szőke 
78*231bb9b4SBenjamin Szőke 	ret = num;
79*231bb9b4SBenjamin Szőke out:
80*231bb9b4SBenjamin Szőke 	nvkm_i2c_aux_release(aux);
81*231bb9b4SBenjamin Szőke 	return ret;
82*231bb9b4SBenjamin Szőke }
83*231bb9b4SBenjamin Szőke 
84*231bb9b4SBenjamin Szőke static u32
85*231bb9b4SBenjamin Szőke nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap)
86*231bb9b4SBenjamin Szőke {
87*231bb9b4SBenjamin Szőke 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
88*231bb9b4SBenjamin Szőke }
89*231bb9b4SBenjamin Szőke 
90*231bb9b4SBenjamin Szőke static const struct i2c_algorithm
91*231bb9b4SBenjamin Szőke nvkm_i2c_aux_i2c_algo = {
92*231bb9b4SBenjamin Szőke 	.master_xfer = nvkm_i2c_aux_i2c_xfer,
93*231bb9b4SBenjamin Szőke 	.functionality = nvkm_i2c_aux_i2c_func
94*231bb9b4SBenjamin Szőke };
95*231bb9b4SBenjamin Szőke 
96*231bb9b4SBenjamin Szőke void
97*231bb9b4SBenjamin Szőke nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor)
98*231bb9b4SBenjamin Szőke {
99*231bb9b4SBenjamin Szőke 	struct nvkm_i2c_pad *pad = aux->pad;
100*231bb9b4SBenjamin Szőke 	AUX_TRACE(aux, "monitor: %s", str_yes_no(monitor));
101*231bb9b4SBenjamin Szőke 	if (monitor)
102*231bb9b4SBenjamin Szőke 		nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX);
103*231bb9b4SBenjamin Szőke 	else
104*231bb9b4SBenjamin Szőke 		nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF);
105*231bb9b4SBenjamin Szőke }
106*231bb9b4SBenjamin Szőke 
107*231bb9b4SBenjamin Szőke void
108*231bb9b4SBenjamin Szőke nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux)
109*231bb9b4SBenjamin Szőke {
110*231bb9b4SBenjamin Szőke 	struct nvkm_i2c_pad *pad = aux->pad;
111*231bb9b4SBenjamin Szőke 	AUX_TRACE(aux, "release");
112*231bb9b4SBenjamin Szőke 	nvkm_i2c_pad_release(pad);
113*231bb9b4SBenjamin Szőke 	mutex_unlock(&aux->mutex);
114*231bb9b4SBenjamin Szőke }
115*231bb9b4SBenjamin Szőke 
116*231bb9b4SBenjamin Szőke int
117*231bb9b4SBenjamin Szőke nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux)
118*231bb9b4SBenjamin Szőke {
119*231bb9b4SBenjamin Szőke 	struct nvkm_i2c_pad *pad = aux->pad;
120*231bb9b4SBenjamin Szőke 	int ret;
121*231bb9b4SBenjamin Szőke 
122*231bb9b4SBenjamin Szőke 	AUX_TRACE(aux, "acquire");
123*231bb9b4SBenjamin Szőke 	mutex_lock(&aux->mutex);
124*231bb9b4SBenjamin Szőke 
125*231bb9b4SBenjamin Szőke 	if (aux->enabled)
126*231bb9b4SBenjamin Szőke 		ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX);
127*231bb9b4SBenjamin Szőke 	else
128*231bb9b4SBenjamin Szőke 		ret = -EIO;
129*231bb9b4SBenjamin Szőke 
130*231bb9b4SBenjamin Szőke 	if (ret)
131*231bb9b4SBenjamin Szőke 		mutex_unlock(&aux->mutex);
132*231bb9b4SBenjamin Szőke 	return ret;
133*231bb9b4SBenjamin Szőke }
134*231bb9b4SBenjamin Szőke 
135*231bb9b4SBenjamin Szőke int
136*231bb9b4SBenjamin Szőke nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type,
137*231bb9b4SBenjamin Szőke 		  u32 addr, u8 *data, u8 *size)
138*231bb9b4SBenjamin Szőke {
139*231bb9b4SBenjamin Szőke 	if (!*size && !aux->func->address_only) {
140*231bb9b4SBenjamin Szőke 		AUX_ERR(aux, "address-only transaction dropped");
141*231bb9b4SBenjamin Szőke 		return -ENOSYS;
142*231bb9b4SBenjamin Szőke 	}
143*231bb9b4SBenjamin Szőke 	return aux->func->xfer(aux, retry, type, addr, data, size);
144*231bb9b4SBenjamin Szőke }
145*231bb9b4SBenjamin Szőke 
146*231bb9b4SBenjamin Szőke int
147*231bb9b4SBenjamin Szőke nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef)
148*231bb9b4SBenjamin Szőke {
149*231bb9b4SBenjamin Szőke 	if (aux->func->lnk_ctl)
150*231bb9b4SBenjamin Szőke 		return aux->func->lnk_ctl(aux, nr, bw, ef);
151*231bb9b4SBenjamin Szőke 	return -ENODEV;
152*231bb9b4SBenjamin Szőke }
153*231bb9b4SBenjamin Szőke 
154*231bb9b4SBenjamin Szőke void
155*231bb9b4SBenjamin Szőke nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux)
156*231bb9b4SBenjamin Szőke {
157*231bb9b4SBenjamin Szőke 	struct nvkm_i2c_aux *aux = *paux;
158*231bb9b4SBenjamin Szőke 	if (aux && !WARN_ON(!aux->func)) {
159*231bb9b4SBenjamin Szőke 		AUX_TRACE(aux, "dtor");
160*231bb9b4SBenjamin Szőke 		list_del(&aux->head);
161*231bb9b4SBenjamin Szőke 		i2c_del_adapter(&aux->i2c);
162*231bb9b4SBenjamin Szőke 		kfree(*paux);
163*231bb9b4SBenjamin Szőke 		*paux = NULL;
164*231bb9b4SBenjamin Szőke 	}
165*231bb9b4SBenjamin Szőke }
166*231bb9b4SBenjamin Szőke 
167*231bb9b4SBenjamin Szőke void
168*231bb9b4SBenjamin Szőke nvkm_i2c_aux_init(struct nvkm_i2c_aux *aux)
169*231bb9b4SBenjamin Szőke {
170*231bb9b4SBenjamin Szőke 	AUX_TRACE(aux, "init");
171*231bb9b4SBenjamin Szőke 	mutex_lock(&aux->mutex);
172*231bb9b4SBenjamin Szőke 	aux->enabled = true;
173*231bb9b4SBenjamin Szőke 	mutex_unlock(&aux->mutex);
174*231bb9b4SBenjamin Szőke }
175*231bb9b4SBenjamin Szőke 
176*231bb9b4SBenjamin Szőke void
177*231bb9b4SBenjamin Szőke nvkm_i2c_aux_fini(struct nvkm_i2c_aux *aux)
178*231bb9b4SBenjamin Szőke {
179*231bb9b4SBenjamin Szőke 	AUX_TRACE(aux, "fini");
180*231bb9b4SBenjamin Szőke 	mutex_lock(&aux->mutex);
181*231bb9b4SBenjamin Szőke 	aux->enabled = false;
182*231bb9b4SBenjamin Szőke 	mutex_unlock(&aux->mutex);
183*231bb9b4SBenjamin Szőke }
184*231bb9b4SBenjamin Szőke 
185*231bb9b4SBenjamin Szőke int
186*231bb9b4SBenjamin Szőke nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func,
187*231bb9b4SBenjamin Szőke 		  struct nvkm_i2c_pad *pad, int id,
188*231bb9b4SBenjamin Szőke 		  struct nvkm_i2c_aux *aux)
189*231bb9b4SBenjamin Szőke {
190*231bb9b4SBenjamin Szőke 	struct nvkm_device *device = pad->i2c->subdev.device;
191*231bb9b4SBenjamin Szőke 
192*231bb9b4SBenjamin Szőke 	aux->func = func;
193*231bb9b4SBenjamin Szőke 	aux->pad = pad;
194*231bb9b4SBenjamin Szőke 	aux->id = id;
195*231bb9b4SBenjamin Szőke 	mutex_init(&aux->mutex);
196*231bb9b4SBenjamin Szőke 	list_add_tail(&aux->head, &pad->i2c->aux);
197*231bb9b4SBenjamin Szőke 	AUX_TRACE(aux, "ctor");
198*231bb9b4SBenjamin Szőke 
199*231bb9b4SBenjamin Szőke 	snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x",
200*231bb9b4SBenjamin Szőke 		 dev_name(device->dev), id);
201*231bb9b4SBenjamin Szőke 	aux->i2c.owner = THIS_MODULE;
202*231bb9b4SBenjamin Szőke 	aux->i2c.dev.parent = device->dev;
203*231bb9b4SBenjamin Szőke 	aux->i2c.algo = &nvkm_i2c_aux_i2c_algo;
204*231bb9b4SBenjamin Szőke 	return i2c_add_adapter(&aux->i2c);
205*231bb9b4SBenjamin Szőke }
206*231bb9b4SBenjamin Szőke 
207*231bb9b4SBenjamin Szőke int
208*231bb9b4SBenjamin Szőke nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func,
209*231bb9b4SBenjamin Szőke 		  struct nvkm_i2c_pad *pad, int id,
210*231bb9b4SBenjamin Szőke 		  struct nvkm_i2c_aux **paux)
211*231bb9b4SBenjamin Szőke {
212*231bb9b4SBenjamin Szőke 	if (!(*paux = kzalloc(sizeof(**paux), GFP_KERNEL)))
213*231bb9b4SBenjamin Szőke 		return -ENOMEM;
214*231bb9b4SBenjamin Szőke 	return nvkm_i2c_aux_ctor(func, pad, id, *paux);
215*231bb9b4SBenjamin Szőke }
216