1 /* $OpenBSD: piic.c,v 1.2 2007/05/20 23:38:52 thib Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Mark Kettenis 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/rwlock.h> 23 #include <sys/proc.h> 24 25 #include <machine/autoconf.h> 26 27 #include <dev/i2c/i2cvar.h> 28 29 #include <arch/macppc/dev/maci2cvar.h> 30 #include <arch/macppc/dev/pm_direct.h> 31 32 struct piic_softc { 33 struct device sc_dev; 34 35 struct rwlock sc_buslock; 36 struct i2c_controller sc_i2c_tag; 37 }; 38 39 int piic_match(struct device *, void *, void *); 40 void piic_attach(struct device *, struct device *, void *); 41 42 struct cfattach piic_ca = { 43 sizeof(struct piic_softc), piic_match, piic_attach 44 }; 45 46 struct cfdriver piic_cd = { 47 NULL, "piic", DV_DULL, 48 }; 49 50 int piic_i2c_acquire_bus(void *, int); 51 void piic_i2c_release_bus(void *, int); 52 int piic_i2c_exec(void *, i2c_op_t, i2c_addr_t, 53 const void *, size_t, void *buf, size_t, int); 54 55 int 56 piic_match(struct device *parent, void *cf, void *aux) 57 { 58 return (1); 59 } 60 61 void 62 piic_attach(struct device *parent, struct device *self, void *aux) 63 { 64 struct piic_softc *sc = (struct piic_softc *)self; 65 struct confargs *ca = aux; 66 struct i2cbus_attach_args iba; 67 68 printf("\n"); 69 70 rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); 71 72 sc->sc_i2c_tag.ic_cookie = sc; 73 sc->sc_i2c_tag.ic_acquire_bus = piic_i2c_acquire_bus; 74 sc->sc_i2c_tag.ic_release_bus = piic_i2c_release_bus; 75 sc->sc_i2c_tag.ic_exec = piic_i2c_exec; 76 77 bzero(&iba, sizeof iba); 78 iba.iba_name = "iic"; 79 iba.iba_tag = &sc->sc_i2c_tag; 80 iba.iba_bus_scan = maciic_scan; 81 iba.iba_bus_scan_arg = &ca->ca_node; 82 config_found(&sc->sc_dev, &iba, NULL); 83 } 84 85 int 86 piic_i2c_acquire_bus(void *cookie, int flags) 87 { 88 struct piic_softc *sc = cookie; 89 90 return (rw_enter(&sc->sc_buslock, RW_WRITE)); 91 } 92 93 void 94 piic_i2c_release_bus(void *cookie, int flags) 95 { 96 struct piic_softc *sc = cookie; 97 98 rw_exit(&sc->sc_buslock); 99 } 100 101 int 102 piic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 103 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 104 { 105 u_int8_t pmu_op = PMU_I2C_NORMAL; 106 int retries = 10; 107 PMData p; 108 109 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 5) 110 return (EINVAL); 111 112 if (cmdlen == 0) 113 pmu_op = PMU_I2C_SIMPLE; 114 else if (I2C_OP_READ_P(op)) 115 pmu_op = PMU_I2C_COMBINED; 116 117 p.command = PMU_I2C; 118 p.num_data = 7 + len; 119 p.s_buf = p.r_buf = p.data; 120 121 p.data[0] = addr >> 7; /* bus number */ 122 p.data[1] = pmu_op; 123 p.data[2] = 0; 124 p.data[3] = addr << 1; 125 p.data[4] = *(u_int8_t *)cmdbuf; 126 p.data[5] = addr << 1 | I2C_OP_READ_P(op); 127 p.data[6] = len; 128 memcpy(&p.data[7], buf, len); 129 130 if (pmgrop(&p)) 131 return (EIO); 132 133 while (retries--) { 134 p.command = PMU_I2C; 135 p.num_data = 1; 136 p.s_buf = p.r_buf = p.data; 137 p.data[0] = 0; 138 139 if (pmgrop(&p)) 140 return (EIO); 141 142 if (p.data[0] == 1) 143 break; 144 145 DELAY(10 * 1000); 146 } 147 148 if (I2C_OP_READ_P(op)) 149 memcpy(buf, &p.data[1], len); 150 return (0); 151 } 152