1 /* $OpenBSD: piic.c,v 1.3 2011/06/16 10:44:33 mpi 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 struct confargs *ca = aux; 59 60 if (strcmp(ca->ca_name, "piic") != 0) 61 return (0); 62 63 return (1); 64 } 65 66 void 67 piic_attach(struct device *parent, struct device *self, void *aux) 68 { 69 struct piic_softc *sc = (struct piic_softc *)self; 70 struct confargs *ca = aux; 71 struct i2cbus_attach_args iba; 72 73 printf("\n"); 74 75 rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); 76 77 sc->sc_i2c_tag.ic_cookie = sc; 78 sc->sc_i2c_tag.ic_acquire_bus = piic_i2c_acquire_bus; 79 sc->sc_i2c_tag.ic_release_bus = piic_i2c_release_bus; 80 sc->sc_i2c_tag.ic_exec = piic_i2c_exec; 81 82 bzero(&iba, sizeof iba); 83 iba.iba_name = "iic"; 84 iba.iba_tag = &sc->sc_i2c_tag; 85 iba.iba_bus_scan = maciic_scan; 86 iba.iba_bus_scan_arg = &ca->ca_node; 87 config_found(&sc->sc_dev, &iba, NULL); 88 } 89 90 int 91 piic_i2c_acquire_bus(void *cookie, int flags) 92 { 93 struct piic_softc *sc = cookie; 94 95 return (rw_enter(&sc->sc_buslock, RW_WRITE)); 96 } 97 98 void 99 piic_i2c_release_bus(void *cookie, int flags) 100 { 101 struct piic_softc *sc = cookie; 102 103 rw_exit(&sc->sc_buslock); 104 } 105 106 int 107 piic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 108 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 109 { 110 u_int8_t pmu_op = PMU_I2C_NORMAL; 111 int retries = 10; 112 PMData p; 113 114 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 5) 115 return (EINVAL); 116 117 if (cmdlen == 0) 118 pmu_op = PMU_I2C_SIMPLE; 119 else if (I2C_OP_READ_P(op)) 120 pmu_op = PMU_I2C_COMBINED; 121 122 p.command = PMU_I2C; 123 p.num_data = 7 + len; 124 p.s_buf = p.r_buf = p.data; 125 126 p.data[0] = addr >> 7; /* bus number */ 127 p.data[1] = pmu_op; 128 p.data[2] = 0; 129 p.data[3] = addr << 1; 130 p.data[4] = *(u_int8_t *)cmdbuf; 131 p.data[5] = addr << 1 | I2C_OP_READ_P(op); 132 p.data[6] = len; 133 memcpy(&p.data[7], buf, len); 134 135 if (pmgrop(&p)) 136 return (EIO); 137 138 while (retries--) { 139 p.command = PMU_I2C; 140 p.num_data = 1; 141 p.s_buf = p.r_buf = p.data; 142 p.data[0] = 0; 143 144 if (pmgrop(&p)) 145 return (EIO); 146 147 if (p.data[0] == 1) 148 break; 149 150 DELAY(10 * 1000); 151 } 152 153 if (I2C_OP_READ_P(op)) 154 memcpy(buf, &p.data[1], len); 155 return (0); 156 } 157