xref: /freebsd/sys/compat/linuxkpi/common/src/linux_i2cbb.c (revision 25d21a845223ffad189fd2a7831ebf5e298b628a)
11961a14aSEmmanuel Vadot /*-
21961a14aSEmmanuel Vadot  * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
31961a14aSEmmanuel Vadot  *
41961a14aSEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
51961a14aSEmmanuel Vadot  * modification, are permitted provided that the following conditions
61961a14aSEmmanuel Vadot  * are met:
71961a14aSEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
81961a14aSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
91961a14aSEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
101961a14aSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
111961a14aSEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
121961a14aSEmmanuel Vadot  *
131961a14aSEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
141961a14aSEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151961a14aSEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161961a14aSEmmanuel Vadot  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
171961a14aSEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181961a14aSEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191961a14aSEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201961a14aSEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211961a14aSEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221961a14aSEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231961a14aSEmmanuel Vadot  * SUCH DAMAGE.
241961a14aSEmmanuel Vadot  *
251961a14aSEmmanuel Vadot  */
261961a14aSEmmanuel Vadot 
271961a14aSEmmanuel Vadot #include <sys/cdefs.h>
281961a14aSEmmanuel Vadot __FBSDID("$FreeBSD$");
291961a14aSEmmanuel Vadot 
301961a14aSEmmanuel Vadot #include <sys/param.h>
311961a14aSEmmanuel Vadot #include <sys/systm.h>
321961a14aSEmmanuel Vadot #include <sys/bus.h>
331961a14aSEmmanuel Vadot #include <sys/malloc.h>
341961a14aSEmmanuel Vadot 
351961a14aSEmmanuel Vadot #include <dev/iicbus/iicbus.h>
361961a14aSEmmanuel Vadot #include <dev/iicbus/iiconf.h>
371961a14aSEmmanuel Vadot 
381961a14aSEmmanuel Vadot #include <linux/device.h>
391961a14aSEmmanuel Vadot #include <linux/i2c.h>
401961a14aSEmmanuel Vadot #include <linux/i2c-algo-bit.h>
411961a14aSEmmanuel Vadot #include <linux/list.h>
421961a14aSEmmanuel Vadot #include <linux/pci.h>
431961a14aSEmmanuel Vadot 
441961a14aSEmmanuel Vadot #include "iicbb_if.h"
451961a14aSEmmanuel Vadot #include "lkpi_iic_if.h"
461961a14aSEmmanuel Vadot 
471961a14aSEmmanuel Vadot static void lkpi_iicbb_setsda(device_t dev, int val);
481961a14aSEmmanuel Vadot static void lkpi_iicbb_setscl(device_t dev, int val);
491961a14aSEmmanuel Vadot static int lkpi_iicbb_getscl(device_t dev);
501961a14aSEmmanuel Vadot static int lkpi_iicbb_getsda(device_t dev);
511961a14aSEmmanuel Vadot static int lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr);
521961a14aSEmmanuel Vadot 
531961a14aSEmmanuel Vadot struct lkpi_iicbb_softc {
541961a14aSEmmanuel Vadot 	device_t		iicbb;
551961a14aSEmmanuel Vadot 	struct i2c_adapter	*adapter;
561961a14aSEmmanuel Vadot };
571961a14aSEmmanuel Vadot 
581961a14aSEmmanuel Vadot static int
591961a14aSEmmanuel Vadot lkpi_iicbb_probe(device_t dev)
601961a14aSEmmanuel Vadot {
611961a14aSEmmanuel Vadot 
621961a14aSEmmanuel Vadot 	device_set_desc(dev, "LinuxKPI I2CBB");
631961a14aSEmmanuel Vadot 	return (BUS_PROBE_NOWILDCARD);
641961a14aSEmmanuel Vadot }
651961a14aSEmmanuel Vadot 
661961a14aSEmmanuel Vadot static int
671961a14aSEmmanuel Vadot lkpi_iicbb_attach(device_t dev)
681961a14aSEmmanuel Vadot {
691961a14aSEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
701961a14aSEmmanuel Vadot 
711961a14aSEmmanuel Vadot 	sc = device_get_softc(dev);
721961a14aSEmmanuel Vadot 	sc->iicbb = device_add_child(dev, "iicbb", -1);
731961a14aSEmmanuel Vadot 	if (sc->iicbb == NULL) {
741961a14aSEmmanuel Vadot 		device_printf(dev, "Couldn't add iicbb child, aborting\n");
751961a14aSEmmanuel Vadot 		return (ENXIO);
761961a14aSEmmanuel Vadot 	}
771961a14aSEmmanuel Vadot 	bus_generic_attach(dev);
781961a14aSEmmanuel Vadot 	return (0);
791961a14aSEmmanuel Vadot }
801961a14aSEmmanuel Vadot 
811961a14aSEmmanuel Vadot static int
821961a14aSEmmanuel Vadot lkpi_iicbb_detach(device_t dev)
831961a14aSEmmanuel Vadot {
841961a14aSEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
851961a14aSEmmanuel Vadot 
861961a14aSEmmanuel Vadot 	sc = device_get_softc(dev);
871961a14aSEmmanuel Vadot 	if (sc->iicbb)
881961a14aSEmmanuel Vadot 		device_delete_child(dev, sc->iicbb);
891961a14aSEmmanuel Vadot 	return (0);
901961a14aSEmmanuel Vadot }
911961a14aSEmmanuel Vadot 
921961a14aSEmmanuel Vadot static int
931961a14aSEmmanuel Vadot lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter)
941961a14aSEmmanuel Vadot {
951961a14aSEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
961961a14aSEmmanuel Vadot 
971961a14aSEmmanuel Vadot 	sc = device_get_softc(dev);
981961a14aSEmmanuel Vadot 	sc->adapter = adapter;
991961a14aSEmmanuel Vadot 
1001961a14aSEmmanuel Vadot 	return (0);
1011961a14aSEmmanuel Vadot }
1021961a14aSEmmanuel Vadot 
103*25d21a84SEmmanuel Vadot static struct i2c_adapter *
104*25d21a84SEmmanuel Vadot lkpi_iicbb_get_adapter(device_t dev)
105*25d21a84SEmmanuel Vadot {
106*25d21a84SEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
107*25d21a84SEmmanuel Vadot 
108*25d21a84SEmmanuel Vadot 	sc = device_get_softc(dev);
109*25d21a84SEmmanuel Vadot 	return (sc->adapter);
110*25d21a84SEmmanuel Vadot }
111*25d21a84SEmmanuel Vadot 
1121961a14aSEmmanuel Vadot static device_method_t lkpi_iicbb_methods[] = {
1131961a14aSEmmanuel Vadot 	/* device interface */
1141961a14aSEmmanuel Vadot 	DEVMETHOD(device_probe,		lkpi_iicbb_probe),
1151961a14aSEmmanuel Vadot 	DEVMETHOD(device_attach,	lkpi_iicbb_attach),
1161961a14aSEmmanuel Vadot 	DEVMETHOD(device_detach,	lkpi_iicbb_detach),
1171961a14aSEmmanuel Vadot 	DEVMETHOD(device_suspend,	bus_generic_suspend),
1181961a14aSEmmanuel Vadot 	DEVMETHOD(device_resume,	bus_generic_resume),
1191961a14aSEmmanuel Vadot 
1201961a14aSEmmanuel Vadot 	/* iicbb interface */
1211961a14aSEmmanuel Vadot 	DEVMETHOD(iicbb_setsda,		lkpi_iicbb_setsda),
1221961a14aSEmmanuel Vadot 	DEVMETHOD(iicbb_setscl,		lkpi_iicbb_setscl),
1231961a14aSEmmanuel Vadot 	DEVMETHOD(iicbb_getsda,		lkpi_iicbb_getsda),
1241961a14aSEmmanuel Vadot 	DEVMETHOD(iicbb_getscl,		lkpi_iicbb_getscl),
1251961a14aSEmmanuel Vadot 	DEVMETHOD(iicbb_reset,		lkpi_iicbb_reset),
1261961a14aSEmmanuel Vadot 
1271961a14aSEmmanuel Vadot 	/* lkpi_iicbb interface */
1281961a14aSEmmanuel Vadot 	DEVMETHOD(lkpi_iic_add_adapter,	lkpi_iicbb_add_adapter),
129*25d21a84SEmmanuel Vadot 	DEVMETHOD(lkpi_iic_get_adapter,	lkpi_iicbb_get_adapter),
1301961a14aSEmmanuel Vadot 
1311961a14aSEmmanuel Vadot 	DEVMETHOD_END
1321961a14aSEmmanuel Vadot };
1331961a14aSEmmanuel Vadot 
1341961a14aSEmmanuel Vadot driver_t lkpi_iicbb_driver = {
1351961a14aSEmmanuel Vadot 	"lkpi_iicbb",
1361961a14aSEmmanuel Vadot 	lkpi_iicbb_methods,
1371961a14aSEmmanuel Vadot 	sizeof(struct lkpi_iicbb_softc),
1381961a14aSEmmanuel Vadot };
1391961a14aSEmmanuel Vadot 
140a65d0774SJohn Baldwin DRIVER_MODULE(lkpi_iicbb, lkpi_iic, lkpi_iicbb_driver, 0, 0);
1418c13dd83SJohn Baldwin DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, 0, 0);
1421961a14aSEmmanuel Vadot MODULE_DEPEND(lkpi_iicbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
1431961a14aSEmmanuel Vadot 
1441961a14aSEmmanuel Vadot static void
1451961a14aSEmmanuel Vadot lkpi_iicbb_setsda(device_t dev, int val)
1461961a14aSEmmanuel Vadot {
1471961a14aSEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
1481961a14aSEmmanuel Vadot 	struct i2c_algo_bit_data *algo_data;
1491961a14aSEmmanuel Vadot 
1501961a14aSEmmanuel Vadot 	sc = device_get_softc(dev);
1511961a14aSEmmanuel Vadot 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
1521961a14aSEmmanuel Vadot 	algo_data->setsda(algo_data->data, val);
1531961a14aSEmmanuel Vadot 	cpu_spinwait();
1541961a14aSEmmanuel Vadot 	DELAY(algo_data->udelay);
1551961a14aSEmmanuel Vadot }
1561961a14aSEmmanuel Vadot 
1571961a14aSEmmanuel Vadot static void
1581961a14aSEmmanuel Vadot lkpi_iicbb_setscl(device_t dev, int val)
1591961a14aSEmmanuel Vadot {
1601961a14aSEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
1611961a14aSEmmanuel Vadot 	struct i2c_algo_bit_data *algo_data;
1621961a14aSEmmanuel Vadot 
1631961a14aSEmmanuel Vadot 	sc = device_get_softc(dev);
1641961a14aSEmmanuel Vadot 
1651961a14aSEmmanuel Vadot 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
1661961a14aSEmmanuel Vadot 	algo_data->setscl(algo_data->data, val);
1671961a14aSEmmanuel Vadot 	cpu_spinwait();
1681961a14aSEmmanuel Vadot 	DELAY(algo_data->udelay);
1691961a14aSEmmanuel Vadot }
1701961a14aSEmmanuel Vadot 
1711961a14aSEmmanuel Vadot static int
1721961a14aSEmmanuel Vadot lkpi_iicbb_getscl(device_t dev)
1731961a14aSEmmanuel Vadot {
1741961a14aSEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
1751961a14aSEmmanuel Vadot 	struct i2c_algo_bit_data *algo_data;
1761961a14aSEmmanuel Vadot 	unsigned long orig_ticks;
1771961a14aSEmmanuel Vadot 	int ret = 0;
1781961a14aSEmmanuel Vadot 
1791961a14aSEmmanuel Vadot 	sc = device_get_softc(dev);
1801961a14aSEmmanuel Vadot 
1811961a14aSEmmanuel Vadot 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
1821961a14aSEmmanuel Vadot 
1831961a14aSEmmanuel Vadot 	orig_ticks = ticks;
1841961a14aSEmmanuel Vadot 	while (!ret) {
1851961a14aSEmmanuel Vadot 		ret = algo_data->getscl(algo_data->data);
1861961a14aSEmmanuel Vadot 
1871961a14aSEmmanuel Vadot 		if (ret)
1881961a14aSEmmanuel Vadot 			break;
1891961a14aSEmmanuel Vadot 
1901961a14aSEmmanuel Vadot 		if (ticks > orig_ticks + algo_data->timeout)
1911961a14aSEmmanuel Vadot 			return (ETIMEDOUT);
1921961a14aSEmmanuel Vadot 
1931961a14aSEmmanuel Vadot 		cpu_spinwait();
1941961a14aSEmmanuel Vadot 		DELAY(algo_data->udelay);
1951961a14aSEmmanuel Vadot 	}
1961961a14aSEmmanuel Vadot 	DELAY(algo_data->udelay);
1971961a14aSEmmanuel Vadot 	return (ret);
1981961a14aSEmmanuel Vadot }
1991961a14aSEmmanuel Vadot 
2001961a14aSEmmanuel Vadot static int
2011961a14aSEmmanuel Vadot lkpi_iicbb_getsda(device_t dev)
2021961a14aSEmmanuel Vadot {
2031961a14aSEmmanuel Vadot 	struct lkpi_iicbb_softc *sc;
2041961a14aSEmmanuel Vadot 	struct i2c_algo_bit_data *algo_data;
2051961a14aSEmmanuel Vadot 	int ret = 0;
2061961a14aSEmmanuel Vadot 
2071961a14aSEmmanuel Vadot 	sc = device_get_softc(dev);
2081961a14aSEmmanuel Vadot 	algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
2091961a14aSEmmanuel Vadot 
2101961a14aSEmmanuel Vadot 	cpu_spinwait();
2111961a14aSEmmanuel Vadot 	DELAY(algo_data->udelay);
2121961a14aSEmmanuel Vadot 	ret = algo_data->getsda(algo_data->data);
2131961a14aSEmmanuel Vadot 	cpu_spinwait();
2141961a14aSEmmanuel Vadot 	DELAY(algo_data->udelay);
2151961a14aSEmmanuel Vadot 	return (ret);
2161961a14aSEmmanuel Vadot }
2171961a14aSEmmanuel Vadot 
2181961a14aSEmmanuel Vadot static int
2191961a14aSEmmanuel Vadot lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
2201961a14aSEmmanuel Vadot {
2211961a14aSEmmanuel Vadot 
2221961a14aSEmmanuel Vadot 	return (0);
2231961a14aSEmmanuel Vadot }
2241961a14aSEmmanuel Vadot 
2251961a14aSEmmanuel Vadot int
2261961a14aSEmmanuel Vadot lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
2271961a14aSEmmanuel Vadot {
2281961a14aSEmmanuel Vadot 
2291961a14aSEmmanuel Vadot 	/* TODO: convert from i2c_msg to iic_msg and call IICBUS_TRANFER */
2301961a14aSEmmanuel Vadot 	return (0);
2311961a14aSEmmanuel Vadot }
2321961a14aSEmmanuel Vadot 
2331961a14aSEmmanuel Vadot int
2341961a14aSEmmanuel Vadot lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter)
2351961a14aSEmmanuel Vadot {
2361961a14aSEmmanuel Vadot 	device_t lkpi_iicbb;
2371961a14aSEmmanuel Vadot 	int error;
2381961a14aSEmmanuel Vadot 
2391961a14aSEmmanuel Vadot 	if (bootverbose)
2401961a14aSEmmanuel Vadot 		device_printf(adapter->dev.parent->bsddev,
2411961a14aSEmmanuel Vadot 		    "Adding i2c adapter %s\n", adapter->name);
2421961a14aSEmmanuel Vadot 	lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1);
2431961a14aSEmmanuel Vadot 	if (lkpi_iicbb == NULL) {
2441961a14aSEmmanuel Vadot 		device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n");
2451961a14aSEmmanuel Vadot 		return (ENXIO);
2461961a14aSEmmanuel Vadot 	}
2471961a14aSEmmanuel Vadot 
2481961a14aSEmmanuel Vadot 	error = bus_generic_attach(adapter->dev.parent->bsddev);
2491961a14aSEmmanuel Vadot 	if (error) {
2501961a14aSEmmanuel Vadot 		device_printf(adapter->dev.parent->bsddev,
2511961a14aSEmmanuel Vadot 		  "failed to attach child: error %d\n", error);
2521961a14aSEmmanuel Vadot 		return (ENXIO);
2531961a14aSEmmanuel Vadot 	}
2541961a14aSEmmanuel Vadot 	LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter);
2551961a14aSEmmanuel Vadot 	return (0);
2561961a14aSEmmanuel Vadot }
2571961a14aSEmmanuel Vadot 
258