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