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 static devclass_t lkpi_iicbb_devclass; 125 126 driver_t lkpi_iicbb_driver = { 127 "lkpi_iicbb", 128 lkpi_iicbb_methods, 129 sizeof(struct lkpi_iicbb_softc), 130 }; 131 132 DRIVER_MODULE(lkpi_iicbb, lkpi_iic, lkpi_iicbb_driver, lkpi_iicbb_devclass, 0, 0); 133 DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, iicbb_devclass, 0, 0); 134 MODULE_DEPEND(lkpi_iicbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 135 136 static void 137 lkpi_iicbb_setsda(device_t dev, int val) 138 { 139 struct lkpi_iicbb_softc *sc; 140 struct i2c_algo_bit_data *algo_data; 141 142 sc = device_get_softc(dev); 143 algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data; 144 algo_data->setsda(algo_data->data, val); 145 cpu_spinwait(); 146 DELAY(algo_data->udelay); 147 } 148 149 static void 150 lkpi_iicbb_setscl(device_t dev, int val) 151 { 152 struct lkpi_iicbb_softc *sc; 153 struct i2c_algo_bit_data *algo_data; 154 155 sc = device_get_softc(dev); 156 157 algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data; 158 algo_data->setscl(algo_data->data, val); 159 cpu_spinwait(); 160 DELAY(algo_data->udelay); 161 } 162 163 static int 164 lkpi_iicbb_getscl(device_t dev) 165 { 166 struct lkpi_iicbb_softc *sc; 167 struct i2c_algo_bit_data *algo_data; 168 unsigned long orig_ticks; 169 int ret = 0; 170 171 sc = device_get_softc(dev); 172 173 algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data; 174 175 orig_ticks = ticks; 176 while (!ret) { 177 ret = algo_data->getscl(algo_data->data); 178 179 if (ret) 180 break; 181 182 if (ticks > orig_ticks + algo_data->timeout) 183 return (ETIMEDOUT); 184 185 cpu_spinwait(); 186 DELAY(algo_data->udelay); 187 } 188 DELAY(algo_data->udelay); 189 return (ret); 190 } 191 192 static int 193 lkpi_iicbb_getsda(device_t dev) 194 { 195 struct lkpi_iicbb_softc *sc; 196 struct i2c_algo_bit_data *algo_data; 197 int ret = 0; 198 199 sc = device_get_softc(dev); 200 algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data; 201 202 cpu_spinwait(); 203 DELAY(algo_data->udelay); 204 ret = algo_data->getsda(algo_data->data); 205 cpu_spinwait(); 206 DELAY(algo_data->udelay); 207 return (ret); 208 } 209 210 static int 211 lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 212 { 213 214 return (0); 215 } 216 217 int 218 lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs) 219 { 220 221 /* TODO: convert from i2c_msg to iic_msg and call IICBUS_TRANFER */ 222 return (0); 223 } 224 225 int 226 lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter) 227 { 228 device_t lkpi_iicbb; 229 int error; 230 231 if (bootverbose) 232 device_printf(adapter->dev.parent->bsddev, 233 "Adding i2c adapter %s\n", adapter->name); 234 lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1); 235 if (lkpi_iicbb == NULL) { 236 device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n"); 237 return (ENXIO); 238 } 239 240 error = bus_generic_attach(adapter->dev.parent->bsddev); 241 if (error) { 242 device_printf(adapter->dev.parent->bsddev, 243 "failed to attach child: error %d\n", error); 244 return (ENXIO); 245 } 246 LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter); 247 return (0); 248 } 249 250