1 /*- 2 * Copyright (c) 1998 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 * 28 */ 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/module.h> 32 #include <sys/bus.h> 33 34 #include <dev/iicbus/iiconf.h> 35 #include <dev/iicbus/iicbus.h> 36 #include "iicbus_if.h" 37 38 /* 39 * iicbus_intr() 40 */ 41 void 42 iicbus_intr(device_t bus, int event, char *buf) 43 { 44 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 45 46 /* call owner's intr routine */ 47 if (sc->owner) 48 IICBUS_INTR(sc->owner, event, buf); 49 50 return; 51 } 52 53 /* 54 * iicbus_alloc_bus() 55 * 56 * Allocate a new bus connected to the given parent device 57 */ 58 device_t 59 iicbus_alloc_bus(device_t parent) 60 { 61 device_t child; 62 63 /* add the bus to the parent */ 64 child = device_add_child(parent, "iicbus", -1); 65 66 return (child); 67 } 68 69 static int 70 iicbus_poll(struct iicbus_softc *sc, int how) 71 { 72 int error; 73 74 switch (how) { 75 case (IIC_WAIT | IIC_INTR): 76 error = tsleep(sc, IICPRI|PCATCH, "iicreq", 0); 77 break; 78 79 case (IIC_WAIT | IIC_NOINTR): 80 error = tsleep(sc, IICPRI, "iicreq", 0); 81 break; 82 83 default: 84 return (EWOULDBLOCK); 85 break; 86 } 87 88 return (error); 89 } 90 91 /* 92 * iicbus_request_bus() 93 * 94 * Allocate the device to perform transfers. 95 * 96 * how : IIC_WAIT or IIC_DONTWAIT 97 */ 98 int 99 iicbus_request_bus(device_t bus, device_t dev, int how) 100 { 101 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 102 int s, error = 0; 103 104 /* first, ask the underlying layers if the request is ok */ 105 do { 106 error = IICBUS_CALLBACK(device_get_parent(bus), 107 IIC_REQUEST_BUS, (caddr_t)&how); 108 if (error) 109 error = iicbus_poll(sc, how); 110 } while (error == EWOULDBLOCK); 111 112 while (!error) { 113 s = splhigh(); 114 if (sc->owner && sc->owner != dev) { 115 splx(s); 116 117 error = iicbus_poll(sc, how); 118 } else { 119 sc->owner = dev; 120 121 splx(s); 122 return (0); 123 } 124 125 /* free any allocated resource */ 126 if (error) 127 IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, 128 (caddr_t)&how); 129 } 130 131 return (error); 132 } 133 134 /* 135 * iicbus_release_bus() 136 * 137 * Release the device allocated with iicbus_request_dev() 138 */ 139 int 140 iicbus_release_bus(device_t bus, device_t dev) 141 { 142 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 143 int s, error; 144 145 /* first, ask the underlying layers if the release is ok */ 146 error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL); 147 148 if (error) 149 return (error); 150 151 s = splhigh(); 152 if (sc->owner != dev) { 153 splx(s); 154 return (EACCES); 155 } 156 157 sc->owner = 0; 158 splx(s); 159 160 /* wakeup waiting processes */ 161 wakeup(sc); 162 163 return (0); 164 } 165 166 /* 167 * iicbus_started() 168 * 169 * Test if the iicbus is started by the controller 170 */ 171 int 172 iicbus_started(device_t bus) 173 { 174 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 175 176 return (sc->started); 177 } 178 179 /* 180 * iicbus_start() 181 * 182 * Send start condition to the slave addressed by 'slave' 183 */ 184 int 185 iicbus_start(device_t bus, u_char slave, int timeout) 186 { 187 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 188 int error = 0; 189 190 if (sc->started) 191 return (EINVAL); /* bus already started */ 192 193 if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout))) 194 sc->started = slave; 195 else 196 sc->started = 0; 197 198 return (error); 199 } 200 201 /* 202 * iicbus_repeated_start() 203 * 204 * Send start condition to the slave addressed by 'slave' 205 */ 206 int 207 iicbus_repeated_start(device_t bus, u_char slave, int timeout) 208 { 209 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 210 int error = 0; 211 212 if (!sc->started) 213 return (EINVAL); /* bus should have been already started */ 214 215 if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout))) 216 sc->started = slave; 217 else 218 sc->started = 0; 219 220 return (error); 221 } 222 223 /* 224 * iicbus_stop() 225 * 226 * Send stop condition to the bus 227 */ 228 int 229 iicbus_stop(device_t bus) 230 { 231 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 232 int error = 0; 233 234 if (!sc->started) 235 return (EINVAL); /* bus not started */ 236 237 error = IICBUS_STOP(device_get_parent(bus)); 238 239 /* refuse any further access */ 240 sc->started = 0; 241 242 return (error); 243 } 244 245 /* 246 * iicbus_write() 247 * 248 * Write a block of data to the slave previously started by 249 * iicbus_start() call 250 */ 251 int 252 iicbus_write(device_t bus, char *buf, int len, int *sent, int timeout) 253 { 254 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 255 256 /* a slave must have been started with the appropriate address */ 257 if (!sc->started || (sc->started & LSB)) 258 return (EINVAL); 259 260 return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout)); 261 } 262 263 /* 264 * iicbus_read() 265 * 266 * Read a block of data from the slave previously started by 267 * iicbus_read() call 268 */ 269 int 270 iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay) 271 { 272 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 273 274 /* a slave must have been started with the appropriate address */ 275 if (!sc->started || !(sc->started & LSB)) 276 return (EINVAL); 277 278 return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay)); 279 } 280 281 /* 282 * iicbus_write_byte() 283 * 284 * Write a byte to the slave previously started by iicbus_start() call 285 */ 286 int 287 iicbus_write_byte(device_t bus, char byte, int timeout) 288 { 289 char data = byte; 290 int sent; 291 292 return (iicbus_write(bus, &data, 1, &sent, timeout)); 293 } 294 295 /* 296 * iicbus_read_byte() 297 * 298 * Read a byte from the slave previously started by iicbus_start() call 299 */ 300 int 301 iicbus_read_byte(device_t bus, char *byte, int timeout) 302 { 303 int read; 304 305 return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout)); 306 } 307 308 /* 309 * iicbus_block_write() 310 * 311 * Write a block of data to slave ; start/stop protocol managed 312 */ 313 int 314 iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent) 315 { 316 u_char addr = slave & ~LSB; 317 int error; 318 319 if ((error = iicbus_start(bus, addr, 0))) 320 return (error); 321 322 error = iicbus_write(bus, buf, len, sent, 0); 323 324 iicbus_stop(bus); 325 326 return (error); 327 } 328 329 /* 330 * iicbus_block_read() 331 * 332 * Read a block of data from slave ; start/stop protocol managed 333 */ 334 int 335 iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read) 336 { 337 u_char addr = slave | LSB; 338 int error; 339 340 if ((error = iicbus_start(bus, addr, 0))) 341 return (error); 342 343 error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0); 344 345 iicbus_stop(bus); 346 347 return (error); 348 } 349 350 /* 351 * iicbus_get_addr() 352 * 353 * Get the I2C 7 bits address of the device 354 */ 355 u_char 356 iicbus_get_addr(device_t dev) 357 { 358 uintptr_t addr; 359 device_t parent = device_get_parent(dev); 360 361 BUS_READ_IVAR(parent, dev, IICBUS_IVAR_ADDR, &addr); 362 363 return ((u_char)addr); 364 } 365 366