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