1 /*-
2  * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  */
26 
27 #include <sys/cdefs.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bus.h>
31 #include <sys/malloc.h>
32 
33 #include <dev/iicbus/iicbus.h>
34 #include <dev/iicbus/iiconf.h>
35 
36 #include <linux/device.h>
37 #include <linux/i2c.h>
38 #include <linux/i2c-algo-bit.h>
39 #include <linux/list.h>
40 #include <linux/pci.h>
41 
42 #include "iicbus_if.h"
43 #include "iicbb_if.h"
44 #include "lkpi_iic_if.h"
45 
46 static void lkpi_iicbb_setsda(device_t dev, int val);
47 static void lkpi_iicbb_setscl(device_t dev, int val);
48 static int lkpi_iicbb_getscl(device_t dev);
49 static int lkpi_iicbb_getsda(device_t dev);
50 static int lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr);
51 static int lkpi_iicbb_pre_xfer(device_t dev);
52 static void lkpi_iicbb_post_xfer(device_t dev);
53 
54 struct lkpi_iicbb_softc {
55 	device_t		iicbb;
56 	struct i2c_adapter	*adapter;
57 };
58 
59 static struct sx lkpi_sx_i2cbb;
60 
61 static void
62 lkpi_sysinit_i2cbb(void *arg __unused)
63 {
64 
65 	sx_init(&lkpi_sx_i2cbb, "lkpi-i2cbb");
66 }
67 
68 static void
69 lkpi_sysuninit_i2cbb(void *arg __unused)
70 {
71 
72 	sx_destroy(&lkpi_sx_i2cbb);
73 }
74 
75 SYSINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY,
76     lkpi_sysinit_i2cbb, NULL);
77 SYSUNINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY,
78     lkpi_sysuninit_i2cbb, NULL);
79 
80 static int
81 lkpi_iicbb_probe(device_t dev)
82 {
83 
84 	device_set_desc(dev, "LinuxKPI I2CBB");
85 	return (BUS_PROBE_NOWILDCARD);
86 }
87 
88 static int
89 lkpi_iicbb_attach(device_t dev)
90 {
91 	struct lkpi_iicbb_softc *sc;
92 
93 	sc = device_get_softc(dev);
94 	sc->iicbb = device_add_child(dev, "iicbb", -1);
95 	if (sc->iicbb == NULL) {
96 		device_printf(dev, "Couldn't add iicbb child, aborting\n");
97 		return (ENXIO);
98 	}
99 	bus_generic_attach(dev);
100 	return (0);
101 }
102 
103 static int
104 lkpi_iicbb_detach(device_t dev)
105 {
106 	struct lkpi_iicbb_softc *sc;
107 
108 	sc = device_get_softc(dev);
109 	if (sc->iicbb)
110 		device_delete_child(dev, sc->iicbb);
111 	return (0);
112 }
113 
114 static int
115 lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter)
116 {
117 	struct lkpi_iicbb_softc *sc;
118 	struct i2c_algo_bit_data *algo_data;
119 
120 	sc = device_get_softc(dev);
121 	sc->adapter = adapter;
122 
123 	/*
124 	 * Set iicbb timing parameters deriving speed from the protocol delay.
125 	 */
126 	algo_data = adapter->algo_data;
127 	if (algo_data->udelay != 0)
128 		IICBUS_RESET(sc->iicbb, 1000000 / algo_data->udelay, 0, NULL);
129 	return (0);
130 }
131 
132 static struct i2c_adapter *
133 lkpi_iicbb_get_adapter(device_t dev)
134 {
135 	struct lkpi_iicbb_softc *sc;
136 
137 	sc = device_get_softc(dev);
138 	return (sc->adapter);
139 }
140 
141 static device_method_t lkpi_iicbb_methods[] = {
142 	/* device interface */
143 	DEVMETHOD(device_probe,		lkpi_iicbb_probe),
144 	DEVMETHOD(device_attach,	lkpi_iicbb_attach),
145 	DEVMETHOD(device_detach,	lkpi_iicbb_detach),
146 	DEVMETHOD(device_suspend,	bus_generic_suspend),
147 	DEVMETHOD(device_resume,	bus_generic_resume),
148 
149 	/* iicbb interface */
150 	DEVMETHOD(iicbb_setsda,		lkpi_iicbb_setsda),
151 	DEVMETHOD(iicbb_setscl,		lkpi_iicbb_setscl),
152 	DEVMETHOD(iicbb_getsda,		lkpi_iicbb_getsda),
153 	DEVMETHOD(iicbb_getscl,		lkpi_iicbb_getscl),
154 	DEVMETHOD(iicbb_reset,		lkpi_iicbb_reset),
155 	DEVMETHOD(iicbb_pre_xfer,	lkpi_iicbb_pre_xfer),
156 	DEVMETHOD(iicbb_post_xfer,	lkpi_iicbb_post_xfer),
157 
158 	/* lkpi_iicbb interface */
159 	DEVMETHOD(lkpi_iic_add_adapter,	lkpi_iicbb_add_adapter),
160 	DEVMETHOD(lkpi_iic_get_adapter,	lkpi_iicbb_get_adapter),
161 
162 	DEVMETHOD_END
163 };
164 
165 driver_t lkpi_iicbb_driver = {
166 	"lkpi_iicbb",
167 	lkpi_iicbb_methods,
168 	sizeof(struct lkpi_iicbb_softc),
169 };
170 
171 DRIVER_MODULE(lkpi_iicbb, drmn, lkpi_iicbb_driver, 0, 0);
172 DRIVER_MODULE(lkpi_iicbb, drm, lkpi_iicbb_driver, 0, 0);
173 DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, 0, 0);
174 MODULE_DEPEND(linuxkpi, iicbb, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
175 
176 static void
177 lkpi_iicbb_setsda(device_t dev, int val)
178 {
179 	struct lkpi_iicbb_softc *sc;
180 	struct i2c_algo_bit_data *algo_data;
181 
182 	sc = device_get_softc(dev);
183 	algo_data = sc->adapter->algo_data;
184 	algo_data->setsda(algo_data->data, val);
185 }
186 
187 static void
188 lkpi_iicbb_setscl(device_t dev, int val)
189 {
190 	struct lkpi_iicbb_softc *sc;
191 	struct i2c_algo_bit_data *algo_data;
192 
193 	sc = device_get_softc(dev);
194 	algo_data = sc->adapter->algo_data;
195 	algo_data->setscl(algo_data->data, val);
196 }
197 
198 static int
199 lkpi_iicbb_getscl(device_t dev)
200 {
201 	struct lkpi_iicbb_softc *sc;
202 	struct i2c_algo_bit_data *algo_data;
203 	int ret;
204 
205 	sc = device_get_softc(dev);
206 	algo_data = sc->adapter->algo_data;
207 	ret = algo_data->getscl(algo_data->data);
208 	return (ret);
209 }
210 
211 static int
212 lkpi_iicbb_getsda(device_t dev)
213 {
214 	struct lkpi_iicbb_softc *sc;
215 	struct i2c_algo_bit_data *algo_data;
216 	int ret;
217 
218 	sc = device_get_softc(dev);
219 	algo_data = sc->adapter->algo_data;
220 	ret = algo_data->getsda(algo_data->data);
221 	return (ret);
222 }
223 
224 static int
225 lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
226 {
227 
228 	/* That doesn't seems to be supported in linux */
229 	return (0);
230 }
231 
232 static int
233 lkpi_iicbb_pre_xfer(device_t dev)
234 {
235 	struct lkpi_iicbb_softc *sc;
236 	struct i2c_algo_bit_data *algo_data;
237 	int rc = 0;
238 
239 	sc = device_get_softc(dev);
240 	algo_data = sc->adapter->algo_data;
241 	if (algo_data->pre_xfer != 0)
242 		rc = algo_data->pre_xfer(sc->adapter);
243 	return (rc);
244 }
245 
246 static void
247 lkpi_iicbb_post_xfer(device_t dev)
248 {
249 	struct lkpi_iicbb_softc *sc;
250 	struct i2c_algo_bit_data *algo_data;
251 
252 	sc = device_get_softc(dev);
253 	algo_data = sc->adapter->algo_data;
254 	if (algo_data->post_xfer != NULL)
255 		algo_data->post_xfer(sc->adapter);
256 }
257 
258 int
259 lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
260     int nmsgs)
261 {
262 	struct iic_msg *bsd_msgs;
263 	int ret = ENXIO;
264 
265 	linux_set_current(curthread);
266 
267 	bsd_msgs = malloc(sizeof(struct iic_msg) * nmsgs,
268 	    M_DEVBUF, M_WAITOK | M_ZERO);
269 
270 	for (int i = 0; i < nmsgs; i++) {
271 		bsd_msgs[i].slave = msgs[i].addr << 1;
272 		bsd_msgs[i].len = msgs[i].len;
273 		bsd_msgs[i].buf = msgs[i].buf;
274 		if (msgs[i].flags & I2C_M_RD)
275 			bsd_msgs[i].flags |= IIC_M_RD;
276 		if (msgs[i].flags & I2C_M_NOSTART)
277 			bsd_msgs[i].flags |= IIC_M_NOSTART;
278 	}
279 
280 	for (int unit = 0; ; unit++) {
281 		device_t child;
282 		struct lkpi_iicbb_softc *sc;
283 
284 		child = device_find_child(adapter->dev.parent->bsddev,
285 		    "lkpi_iicbb", unit);
286 		if (child == NULL)
287 			break;
288 		if (adapter == LKPI_IIC_GET_ADAPTER(child)) {
289 			sc = device_get_softc(child);
290 			ret = IICBUS_TRANSFER(sc->iicbb, bsd_msgs, nmsgs);
291 			ret = iic2errno(ret);
292 			break;
293 		}
294 	}
295 
296 	free(bsd_msgs, M_DEVBUF);
297 
298 	if (ret != 0)
299 		return (-ret);
300 	return (nmsgs);
301 }
302 
303 int
304 lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter)
305 {
306 	device_t lkpi_iicbb;
307 	int error;
308 
309 	if (bootverbose)
310 		device_printf(adapter->dev.parent->bsddev,
311 		    "Adding i2c adapter %s\n", adapter->name);
312 	sx_xlock(&lkpi_sx_i2cbb);
313 	lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1);
314 	if (lkpi_iicbb == NULL) {
315 		device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n");
316 		sx_xunlock(&lkpi_sx_i2cbb);
317 		return (ENXIO);
318 	}
319 
320 	bus_topo_lock();
321 	error = bus_generic_attach(adapter->dev.parent->bsddev);
322 	bus_topo_unlock();
323 	if (error) {
324 		device_printf(adapter->dev.parent->bsddev,
325 		  "failed to attach child: error %d\n", error);
326 		sx_xunlock(&lkpi_sx_i2cbb);
327 		return (ENXIO);
328 	}
329 	LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter);
330 	sx_xunlock(&lkpi_sx_i2cbb);
331 	return (0);
332 }
333