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