xref: /freebsd/sys/compat/linuxkpi/common/src/linux_i2cbb.c (revision 924226fba12cc9a228c73b956e1b7fa24c60b055)
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 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/malloc.h>
34 
35 #include <dev/iicbus/iicbus.h>
36 #include <dev/iicbus/iiconf.h>
37 
38 #include <linux/device.h>
39 #include <linux/i2c.h>
40 #include <linux/i2c-algo-bit.h>
41 #include <linux/list.h>
42 #include <linux/pci.h>
43 
44 #include "iicbb_if.h"
45 #include "lkpi_iic_if.h"
46 
47 static void lkpi_iicbb_setsda(device_t dev, int val);
48 static void lkpi_iicbb_setscl(device_t dev, int val);
49 static int lkpi_iicbb_getscl(device_t dev);
50 static int lkpi_iicbb_getsda(device_t dev);
51 static int lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr);
52 
53 struct lkpi_iicbb_softc {
54 	device_t		iicbb;
55 	struct i2c_adapter	*adapter;
56 };
57 
58 static int
59 lkpi_iicbb_probe(device_t dev)
60 {
61 
62 	device_set_desc(dev, "LinuxKPI I2CBB");
63 	return (BUS_PROBE_NOWILDCARD);
64 }
65 
66 static int
67 lkpi_iicbb_attach(device_t dev)
68 {
69 	struct lkpi_iicbb_softc *sc;
70 
71 	sc = device_get_softc(dev);
72 	sc->iicbb = device_add_child(dev, "iicbb", -1);
73 	if (sc->iicbb == NULL) {
74 		device_printf(dev, "Couldn't add iicbb child, aborting\n");
75 		return (ENXIO);
76 	}
77 	bus_generic_attach(dev);
78 	return (0);
79 }
80 
81 static int
82 lkpi_iicbb_detach(device_t dev)
83 {
84 	struct lkpi_iicbb_softc *sc;
85 
86 	sc = device_get_softc(dev);
87 	if (sc->iicbb)
88 		device_delete_child(dev, sc->iicbb);
89 	return (0);
90 }
91 
92 static int
93 lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter)
94 {
95 	struct lkpi_iicbb_softc *sc;
96 
97 	sc = device_get_softc(dev);
98 	sc->adapter = adapter;
99 
100 	return (0);
101 }
102 
103 static struct i2c_adapter *
104 lkpi_iicbb_get_adapter(device_t dev)
105 {
106 	struct lkpi_iicbb_softc *sc;
107 
108 	sc = device_get_softc(dev);
109 	return (sc->adapter);
110 }
111 
112 static device_method_t lkpi_iicbb_methods[] = {
113 	/* device interface */
114 	DEVMETHOD(device_probe,		lkpi_iicbb_probe),
115 	DEVMETHOD(device_attach,	lkpi_iicbb_attach),
116 	DEVMETHOD(device_detach,	lkpi_iicbb_detach),
117 	DEVMETHOD(device_suspend,	bus_generic_suspend),
118 	DEVMETHOD(device_resume,	bus_generic_resume),
119 
120 	/* iicbb interface */
121 	DEVMETHOD(iicbb_setsda,		lkpi_iicbb_setsda),
122 	DEVMETHOD(iicbb_setscl,		lkpi_iicbb_setscl),
123 	DEVMETHOD(iicbb_getsda,		lkpi_iicbb_getsda),
124 	DEVMETHOD(iicbb_getscl,		lkpi_iicbb_getscl),
125 	DEVMETHOD(iicbb_reset,		lkpi_iicbb_reset),
126 
127 	/* lkpi_iicbb interface */
128 	DEVMETHOD(lkpi_iic_add_adapter,	lkpi_iicbb_add_adapter),
129 	DEVMETHOD(lkpi_iic_get_adapter,	lkpi_iicbb_get_adapter),
130 
131 	DEVMETHOD_END
132 };
133 
134 driver_t lkpi_iicbb_driver = {
135 	"lkpi_iicbb",
136 	lkpi_iicbb_methods,
137 	sizeof(struct lkpi_iicbb_softc),
138 };
139 
140 DRIVER_MODULE(lkpi_iicbb, lkpi_iic, lkpi_iicbb_driver, 0, 0);
141 DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, 0, 0);
142 MODULE_DEPEND(lkpi_iicbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
143 
144 static void
145 lkpi_iicbb_setsda(device_t dev, int val)
146 {
147 	struct lkpi_iicbb_softc *sc;
148 	struct i2c_algo_bit_data *algo_data;
149 
150 	sc = device_get_softc(dev);
151 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
152 	algo_data->setsda(algo_data->data, val);
153 	cpu_spinwait();
154 	DELAY(algo_data->udelay);
155 }
156 
157 static void
158 lkpi_iicbb_setscl(device_t dev, int val)
159 {
160 	struct lkpi_iicbb_softc *sc;
161 	struct i2c_algo_bit_data *algo_data;
162 
163 	sc = device_get_softc(dev);
164 
165 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
166 	algo_data->setscl(algo_data->data, val);
167 	cpu_spinwait();
168 	DELAY(algo_data->udelay);
169 }
170 
171 static int
172 lkpi_iicbb_getscl(device_t dev)
173 {
174 	struct lkpi_iicbb_softc *sc;
175 	struct i2c_algo_bit_data *algo_data;
176 	unsigned long orig_ticks;
177 	int ret = 0;
178 
179 	sc = device_get_softc(dev);
180 
181 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
182 
183 	orig_ticks = ticks;
184 	while (!ret) {
185 		ret = algo_data->getscl(algo_data->data);
186 
187 		if (ret)
188 			break;
189 
190 		if (ticks > orig_ticks + algo_data->timeout)
191 			return (ETIMEDOUT);
192 
193 		cpu_spinwait();
194 		DELAY(algo_data->udelay);
195 	}
196 	DELAY(algo_data->udelay);
197 	return (ret);
198 }
199 
200 static int
201 lkpi_iicbb_getsda(device_t dev)
202 {
203 	struct lkpi_iicbb_softc *sc;
204 	struct i2c_algo_bit_data *algo_data;
205 	int ret = 0;
206 
207 	sc = device_get_softc(dev);
208 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
209 
210 	cpu_spinwait();
211 	DELAY(algo_data->udelay);
212 	ret = algo_data->getsda(algo_data->data);
213 	cpu_spinwait();
214 	DELAY(algo_data->udelay);
215 	return (ret);
216 }
217 
218 static int
219 lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
220 {
221 
222 	return (0);
223 }
224 
225 int
226 lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
227 {
228 
229 	/* TODO: convert from i2c_msg to iic_msg and call IICBUS_TRANFER */
230 	return (0);
231 }
232 
233 int
234 lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter)
235 {
236 	device_t lkpi_iicbb;
237 	int error;
238 
239 	if (bootverbose)
240 		device_printf(adapter->dev.parent->bsddev,
241 		    "Adding i2c adapter %s\n", adapter->name);
242 	lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1);
243 	if (lkpi_iicbb == NULL) {
244 		device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n");
245 		return (ENXIO);
246 	}
247 
248 	error = bus_generic_attach(adapter->dev.parent->bsddev);
249 	if (error) {
250 		device_printf(adapter->dev.parent->bsddev,
251 		  "failed to attach child: error %d\n", error);
252 		return (ENXIO);
253 	}
254 	LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter);
255 	return (0);
256 }
257 
258