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 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 #include <sys/malloc.h> 32 33 #include <dev/iicbus/iicbus.h> 34 #include <dev/iicbus/iiconf.h> 35 36 #include <linux/device.h> 37 #include <linux/i2c.h> 38 #include <linux/i2c-algo-bit.h> 39 #include <linux/list.h> 40 #include <linux/pci.h> 41 42 #include "iicbus_if.h" 43 #include "iicbb_if.h" 44 #include "lkpi_iic_if.h" 45 46 static void lkpi_iicbb_setsda(device_t dev, int val); 47 static void lkpi_iicbb_setscl(device_t dev, int val); 48 static int lkpi_iicbb_getscl(device_t dev); 49 static int lkpi_iicbb_getsda(device_t dev); 50 static int lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr); 51 static int lkpi_iicbb_pre_xfer(device_t dev); 52 static void lkpi_iicbb_post_xfer(device_t dev); 53 54 struct lkpi_iicbb_softc { 55 device_t iicbb; 56 struct i2c_adapter *adapter; 57 }; 58 59 static struct sx lkpi_sx_i2cbb; 60 61 static void 62 lkpi_sysinit_i2cbb(void *arg __unused) 63 { 64 65 sx_init(&lkpi_sx_i2cbb, "lkpi-i2cbb"); 66 } 67 68 static void 69 lkpi_sysuninit_i2cbb(void *arg __unused) 70 { 71 72 sx_destroy(&lkpi_sx_i2cbb); 73 } 74 75 SYSINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY, 76 lkpi_sysinit_i2cbb, NULL); 77 SYSUNINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY, 78 lkpi_sysuninit_i2cbb, NULL); 79 80 static int 81 lkpi_iicbb_probe(device_t dev) 82 { 83 84 device_set_desc(dev, "LinuxKPI I2CBB"); 85 return (BUS_PROBE_NOWILDCARD); 86 } 87 88 static int 89 lkpi_iicbb_attach(device_t dev) 90 { 91 struct lkpi_iicbb_softc *sc; 92 93 sc = device_get_softc(dev); 94 sc->iicbb = device_add_child(dev, "iicbb", -1); 95 if (sc->iicbb == NULL) { 96 device_printf(dev, "Couldn't add iicbb child, aborting\n"); 97 return (ENXIO); 98 } 99 bus_generic_attach(dev); 100 return (0); 101 } 102 103 static int 104 lkpi_iicbb_detach(device_t dev) 105 { 106 struct lkpi_iicbb_softc *sc; 107 108 sc = device_get_softc(dev); 109 if (sc->iicbb) 110 device_delete_child(dev, sc->iicbb); 111 return (0); 112 } 113 114 static int 115 lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter) 116 { 117 struct lkpi_iicbb_softc *sc; 118 struct i2c_algo_bit_data *algo_data; 119 120 sc = device_get_softc(dev); 121 sc->adapter = adapter; 122 123 /* 124 * Set iicbb timing parameters deriving speed from the protocol delay. 125 */ 126 algo_data = adapter->algo_data; 127 if (algo_data->udelay != 0) 128 IICBUS_RESET(sc->iicbb, 1000000 / algo_data->udelay, 0, NULL); 129 return (0); 130 } 131 132 static struct i2c_adapter * 133 lkpi_iicbb_get_adapter(device_t dev) 134 { 135 struct lkpi_iicbb_softc *sc; 136 137 sc = device_get_softc(dev); 138 return (sc->adapter); 139 } 140 141 static device_method_t lkpi_iicbb_methods[] = { 142 /* device interface */ 143 DEVMETHOD(device_probe, lkpi_iicbb_probe), 144 DEVMETHOD(device_attach, lkpi_iicbb_attach), 145 DEVMETHOD(device_detach, lkpi_iicbb_detach), 146 DEVMETHOD(device_suspend, bus_generic_suspend), 147 DEVMETHOD(device_resume, bus_generic_resume), 148 149 /* iicbb interface */ 150 DEVMETHOD(iicbb_setsda, lkpi_iicbb_setsda), 151 DEVMETHOD(iicbb_setscl, lkpi_iicbb_setscl), 152 DEVMETHOD(iicbb_getsda, lkpi_iicbb_getsda), 153 DEVMETHOD(iicbb_getscl, lkpi_iicbb_getscl), 154 DEVMETHOD(iicbb_reset, lkpi_iicbb_reset), 155 DEVMETHOD(iicbb_pre_xfer, lkpi_iicbb_pre_xfer), 156 DEVMETHOD(iicbb_post_xfer, lkpi_iicbb_post_xfer), 157 158 /* lkpi_iicbb interface */ 159 DEVMETHOD(lkpi_iic_add_adapter, lkpi_iicbb_add_adapter), 160 DEVMETHOD(lkpi_iic_get_adapter, lkpi_iicbb_get_adapter), 161 162 DEVMETHOD_END 163 }; 164 165 driver_t lkpi_iicbb_driver = { 166 "lkpi_iicbb", 167 lkpi_iicbb_methods, 168 sizeof(struct lkpi_iicbb_softc), 169 }; 170 171 DRIVER_MODULE(lkpi_iicbb, drmn, lkpi_iicbb_driver, 0, 0); 172 DRIVER_MODULE(lkpi_iicbb, drm, lkpi_iicbb_driver, 0, 0); 173 DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, 0, 0); 174 MODULE_DEPEND(linuxkpi, iicbb, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 175 176 static void 177 lkpi_iicbb_setsda(device_t dev, int val) 178 { 179 struct lkpi_iicbb_softc *sc; 180 struct i2c_algo_bit_data *algo_data; 181 182 sc = device_get_softc(dev); 183 algo_data = sc->adapter->algo_data; 184 algo_data->setsda(algo_data->data, val); 185 } 186 187 static void 188 lkpi_iicbb_setscl(device_t dev, int val) 189 { 190 struct lkpi_iicbb_softc *sc; 191 struct i2c_algo_bit_data *algo_data; 192 193 sc = device_get_softc(dev); 194 algo_data = sc->adapter->algo_data; 195 algo_data->setscl(algo_data->data, val); 196 } 197 198 static int 199 lkpi_iicbb_getscl(device_t dev) 200 { 201 struct lkpi_iicbb_softc *sc; 202 struct i2c_algo_bit_data *algo_data; 203 int ret; 204 205 sc = device_get_softc(dev); 206 algo_data = sc->adapter->algo_data; 207 ret = algo_data->getscl(algo_data->data); 208 return (ret); 209 } 210 211 static int 212 lkpi_iicbb_getsda(device_t dev) 213 { 214 struct lkpi_iicbb_softc *sc; 215 struct i2c_algo_bit_data *algo_data; 216 int ret; 217 218 sc = device_get_softc(dev); 219 algo_data = sc->adapter->algo_data; 220 ret = algo_data->getsda(algo_data->data); 221 return (ret); 222 } 223 224 static int 225 lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 226 { 227 228 /* That doesn't seems to be supported in linux */ 229 return (0); 230 } 231 232 static int 233 lkpi_iicbb_pre_xfer(device_t dev) 234 { 235 struct lkpi_iicbb_softc *sc; 236 struct i2c_algo_bit_data *algo_data; 237 int rc = 0; 238 239 sc = device_get_softc(dev); 240 algo_data = sc->adapter->algo_data; 241 if (algo_data->pre_xfer != 0) 242 rc = algo_data->pre_xfer(sc->adapter); 243 return (rc); 244 } 245 246 static void 247 lkpi_iicbb_post_xfer(device_t dev) 248 { 249 struct lkpi_iicbb_softc *sc; 250 struct i2c_algo_bit_data *algo_data; 251 252 sc = device_get_softc(dev); 253 algo_data = sc->adapter->algo_data; 254 if (algo_data->post_xfer != NULL) 255 algo_data->post_xfer(sc->adapter); 256 } 257 258 int 259 lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, 260 int nmsgs) 261 { 262 struct iic_msg *bsd_msgs; 263 int ret = ENXIO; 264 265 linux_set_current(curthread); 266 267 bsd_msgs = malloc(sizeof(struct iic_msg) * nmsgs, 268 M_DEVBUF, M_WAITOK | M_ZERO); 269 270 for (int i = 0; i < nmsgs; i++) { 271 bsd_msgs[i].slave = msgs[i].addr << 1; 272 bsd_msgs[i].len = msgs[i].len; 273 bsd_msgs[i].buf = msgs[i].buf; 274 if (msgs[i].flags & I2C_M_RD) 275 bsd_msgs[i].flags |= IIC_M_RD; 276 if (msgs[i].flags & I2C_M_NOSTART) 277 bsd_msgs[i].flags |= IIC_M_NOSTART; 278 } 279 280 for (int unit = 0; ; unit++) { 281 device_t child; 282 struct lkpi_iicbb_softc *sc; 283 284 child = device_find_child(adapter->dev.parent->bsddev, 285 "lkpi_iicbb", unit); 286 if (child == NULL) 287 break; 288 if (adapter == LKPI_IIC_GET_ADAPTER(child)) { 289 sc = device_get_softc(child); 290 ret = IICBUS_TRANSFER(sc->iicbb, bsd_msgs, nmsgs); 291 ret = iic2errno(ret); 292 break; 293 } 294 } 295 296 free(bsd_msgs, M_DEVBUF); 297 298 if (ret != 0) 299 return (-ret); 300 return (nmsgs); 301 } 302 303 int 304 lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter) 305 { 306 device_t lkpi_iicbb; 307 int error; 308 309 if (bootverbose) 310 device_printf(adapter->dev.parent->bsddev, 311 "Adding i2c adapter %s\n", adapter->name); 312 sx_xlock(&lkpi_sx_i2cbb); 313 lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1); 314 if (lkpi_iicbb == NULL) { 315 device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n"); 316 sx_xunlock(&lkpi_sx_i2cbb); 317 return (ENXIO); 318 } 319 320 bus_topo_lock(); 321 error = bus_generic_attach(adapter->dev.parent->bsddev); 322 bus_topo_unlock(); 323 if (error) { 324 device_printf(adapter->dev.parent->bsddev, 325 "failed to attach child: error %d\n", error); 326 sx_xunlock(&lkpi_sx_i2cbb); 327 return (ENXIO); 328 } 329 LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter); 330 sx_xunlock(&lkpi_sx_i2cbb); 331 return (0); 332 } 333