xref: /freebsd/sys/compat/linuxkpi/common/src/linux_i2cbb.c (revision bc7512cc58af2e8bbe5bbf5ca0059b1daa1da897)
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 device_method_t lkpi_iicbb_methods[] = {
104 	/* device interface */
105 	DEVMETHOD(device_probe,		lkpi_iicbb_probe),
106 	DEVMETHOD(device_attach,	lkpi_iicbb_attach),
107 	DEVMETHOD(device_detach,	lkpi_iicbb_detach),
108 	DEVMETHOD(device_suspend,	bus_generic_suspend),
109 	DEVMETHOD(device_resume,	bus_generic_resume),
110 
111 	/* iicbb interface */
112 	DEVMETHOD(iicbb_setsda,		lkpi_iicbb_setsda),
113 	DEVMETHOD(iicbb_setscl,		lkpi_iicbb_setscl),
114 	DEVMETHOD(iicbb_getsda,		lkpi_iicbb_getsda),
115 	DEVMETHOD(iicbb_getscl,		lkpi_iicbb_getscl),
116 	DEVMETHOD(iicbb_reset,		lkpi_iicbb_reset),
117 
118 	/* lkpi_iicbb interface */
119 	DEVMETHOD(lkpi_iic_add_adapter,	lkpi_iicbb_add_adapter),
120 
121 	DEVMETHOD_END
122 };
123 
124 driver_t lkpi_iicbb_driver = {
125 	"lkpi_iicbb",
126 	lkpi_iicbb_methods,
127 	sizeof(struct lkpi_iicbb_softc),
128 };
129 
130 DRIVER_MODULE(lkpi_iicbb, lkpi_iic, lkpi_iicbb_driver, 0, 0);
131 DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, 0, 0);
132 MODULE_DEPEND(lkpi_iicbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
133 
134 static void
135 lkpi_iicbb_setsda(device_t dev, int val)
136 {
137 	struct lkpi_iicbb_softc *sc;
138 	struct i2c_algo_bit_data *algo_data;
139 
140 	sc = device_get_softc(dev);
141 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
142 	algo_data->setsda(algo_data->data, val);
143 	cpu_spinwait();
144 	DELAY(algo_data->udelay);
145 }
146 
147 static void
148 lkpi_iicbb_setscl(device_t dev, int val)
149 {
150 	struct lkpi_iicbb_softc *sc;
151 	struct i2c_algo_bit_data *algo_data;
152 
153 	sc = device_get_softc(dev);
154 
155 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
156 	algo_data->setscl(algo_data->data, val);
157 	cpu_spinwait();
158 	DELAY(algo_data->udelay);
159 }
160 
161 static int
162 lkpi_iicbb_getscl(device_t dev)
163 {
164 	struct lkpi_iicbb_softc *sc;
165 	struct i2c_algo_bit_data *algo_data;
166 	unsigned long orig_ticks;
167 	int ret = 0;
168 
169 	sc = device_get_softc(dev);
170 
171 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
172 
173 	orig_ticks = ticks;
174 	while (!ret) {
175 		ret = algo_data->getscl(algo_data->data);
176 
177 		if (ret)
178 			break;
179 
180 		if (ticks > orig_ticks + algo_data->timeout)
181 			return (ETIMEDOUT);
182 
183 		cpu_spinwait();
184 		DELAY(algo_data->udelay);
185 	}
186 	DELAY(algo_data->udelay);
187 	return (ret);
188 }
189 
190 static int
191 lkpi_iicbb_getsda(device_t dev)
192 {
193 	struct lkpi_iicbb_softc *sc;
194 	struct i2c_algo_bit_data *algo_data;
195 	int ret = 0;
196 
197 	sc = device_get_softc(dev);
198 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
199 
200 	cpu_spinwait();
201 	DELAY(algo_data->udelay);
202 	ret = algo_data->getsda(algo_data->data);
203 	cpu_spinwait();
204 	DELAY(algo_data->udelay);
205 	return (ret);
206 }
207 
208 static int
209 lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
210 {
211 
212 	return (0);
213 }
214 
215 int
216 lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
217 {
218 
219 	/* TODO: convert from i2c_msg to iic_msg and call IICBUS_TRANFER */
220 	return (0);
221 }
222 
223 int
224 lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter)
225 {
226 	device_t lkpi_iicbb;
227 	int error;
228 
229 	if (bootverbose)
230 		device_printf(adapter->dev.parent->bsddev,
231 		    "Adding i2c adapter %s\n", adapter->name);
232 	lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1);
233 	if (lkpi_iicbb == NULL) {
234 		device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n");
235 		return (ENXIO);
236 	}
237 
238 	error = bus_generic_attach(adapter->dev.parent->bsddev);
239 	if (error) {
240 		device_printf(adapter->dev.parent->bsddev,
241 		  "failed to attach child: error %d\n", error);
242 		return (ENXIO);
243 	}
244 	LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter);
245 	return (0);
246 }
247 
248