Home | History | Annotate | Line # | Download | only in ic
pcf8584.c revision 1.10
      1 /*	$NetBSD: pcf8584.c,v 1.10 2013/09/15 09:17:28 martin Exp $	*/
      2 /*	$OpenBSD: pcf8584.c,v 1.9 2007/10/20 18:46:21 kettenis Exp $ */
      3 
      4 /*
      5  * Copyright (c) 2006 David Gwynne <dlg (at) openbsd.org>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/param.h>
     21 #include <sys/systm.h>
     22 #include <sys/device.h>
     23 #include <sys/malloc.h>
     24 #include <sys/kernel.h>
     25 #include <sys/rwlock.h>
     26 #include <sys/proc.h>
     27 #include <sys/bus.h>
     28 
     29 #include <dev/i2c/i2cvar.h>
     30 
     31 #include <dev/ic/pcf8584var.h>
     32 
     33 #define PCF_S0			0x00
     34 #define PCF_S1			0x01
     35 #define PCF_S2			0x02
     36 #define PCF_S3			0x03
     37 
     38 #define PCF_CTRL_ACK		(1<<0)
     39 #define PCF_CTRL_STO		(1<<1)
     40 #define PCF_CTRL_STA		(1<<2)
     41 #define PCF_CTRL_ENI		(1<<3)
     42 #define PCF_CTRL_ES2		(1<<4)
     43 #define PCF_CTRL_ES1		(1<<5)
     44 #define PCF_CTRL_ESO		(1<<6)
     45 #define PCF_CTRL_PIN		(1<<7)
     46 
     47 #define PCF_CTRL_START		(PCF_CTRL_PIN | PCF_CTRL_ESO | \
     48     PCF_CTRL_STA | PCF_CTRL_ACK)
     49 #define PCF_CTRL_STOP		(PCF_CTRL_PIN | PCF_CTRL_ESO | \
     50     PCF_CTRL_STO | PCF_CTRL_ACK)
     51 #define PCF_CTRL_REPSTART	(PCF_CTRL_ESO | PCF_CTRL_STA | PCF_CTRL_ACK)
     52 #define PCF_CTRL_IDLE		(PCF_CTRL_PIN | PCF_CTRL_ESO | PCF_CTRL_ACK)
     53 
     54 #define PCF_STAT_nBB		(1<<0)
     55 #define PCF_STAT_LAB		(1<<1)
     56 #define PCF_STAT_AAS		(1<<2)
     57 #define PCF_STAT_AD0		(1<<3)
     58 #define PCF_STAT_LRB		(1<<3)
     59 #define PCF_STAT_BER		(1<<4)
     60 #define PCF_STAT_STS		(1<<5)
     61 #define PCF_STAT_PIN		(1<<7)
     62 
     63 void		pcfiic_init(struct pcfiic_softc *);
     64 int		pcfiic_i2c_acquire_bus(void *, int);
     65 void		pcfiic_i2c_release_bus(void *, int);
     66 int		pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
     67 		    size_t, void *, size_t, int);
     68 
     69 int		pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
     70 		    size_t);
     71 int		pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
     72 		    size_t);
     73 
     74 u_int8_t	pcfiic_read(struct pcfiic_softc *, bus_size_t);
     75 void		pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
     76 void		pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t);
     77 int		pcfiic_wait_nBB(struct pcfiic_softc *);
     78 int		pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
     79 
     80 void
     81 pcfiic_init(struct pcfiic_softc *sc)
     82 {
     83 	/* init S1 */
     84 	pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
     85 	/* own address */
     86 	pcfiic_write(sc, PCF_S0, sc->sc_addr);
     87 
     88 	/* select clock reg */
     89 	pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN|PCF_CTRL_ES1);
     90 	pcfiic_write(sc, PCF_S0, sc->sc_clock);
     91 
     92 	pcfiic_write(sc, PCF_S1, PCF_CTRL_IDLE);
     93 
     94 	delay(200000);	/* Multi-Master mode, wait for longest i2c message */
     95 }
     96 
     97 void
     98 pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
     99     int swapregs)
    100 {
    101 	struct i2cbus_attach_args		iba;
    102 
    103 	if (swapregs) {
    104 		sc->sc_regmap[PCF_S1] = PCF_S0;
    105 		sc->sc_regmap[PCF_S0] = PCF_S1;
    106 	} else {
    107 		sc->sc_regmap[PCF_S0] = PCF_S0;
    108 		sc->sc_regmap[PCF_S1] = PCF_S1;
    109 	}
    110 	sc->sc_clock = clock;
    111 	sc->sc_addr = addr;
    112 
    113 	pcfiic_init(sc);
    114 
    115 	printf("\n");
    116 
    117 	if (sc->sc_master)
    118 		pcfiic_choose_bus(sc, 0);
    119 
    120 	rw_init(&sc->sc_lock);
    121 	sc->sc_i2c.ic_cookie = sc;
    122 	sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus;
    123 	sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus;
    124 	sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
    125 
    126 	bzero(&iba, sizeof(iba));
    127 	iba.iba_tag = &sc->sc_i2c;
    128 	config_found(sc->sc_dev, &iba, iicbus_print);
    129 }
    130 
    131 int
    132 pcfiic_intr(void *arg)
    133 {
    134 	return (0);
    135 }
    136 
    137 int
    138 pcfiic_i2c_acquire_bus(void *arg, int flags)
    139 {
    140 	struct pcfiic_softc	*sc = arg;
    141 
    142 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
    143 		return (0);
    144 
    145 	rw_enter(&sc->sc_lock, RW_WRITER);
    146 	return 0;
    147 }
    148 
    149 void
    150 pcfiic_i2c_release_bus(void *arg, int flags)
    151 {
    152 	struct pcfiic_softc	*sc = arg;
    153 
    154 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
    155 		return;
    156 
    157 	rw_exit(&sc->sc_lock);
    158 }
    159 
    160 int
    161 pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
    162     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
    163 {
    164 	struct pcfiic_softc	*sc = arg;
    165 	int			ret = 0;
    166 
    167 #if 0
    168         printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
    169             device_xname(sc->sc_dev), op, addr, (int)cmdlen, (int)len, flags);
    170 #endif
    171 
    172 	if (cold || sc->sc_poll)
    173 		flags |= I2C_F_POLL;
    174 
    175 	if (sc->sc_master)
    176 		pcfiic_choose_bus(sc, addr >> 7);
    177 
    178 	if (cmdlen > 0)
    179 		if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0)
    180 			return (1);
    181 
    182 	if (len > 0) {
    183 		if (I2C_OP_WRITE_P(op))
    184 			ret = pcfiic_xmit(sc, addr & 0x7f, buf, len);
    185 		else
    186 			ret = pcfiic_recv(sc, addr & 0x7f, buf, len);
    187 	}
    188 	return (ret);
    189 }
    190 
    191 int
    192 pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
    193     size_t len)
    194 {
    195 	int			i, err = 0;
    196 	volatile u_int8_t	r;
    197 
    198 	if (pcfiic_wait_nBB(sc) != 0)
    199 		return (1);
    200 
    201 	pcfiic_write(sc, PCF_S0, addr << 1);
    202 	pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
    203 
    204 	for (i = 0; i <= len; i++) {
    205 		if (pcfiic_wait_pin(sc, &r) != 0) {
    206 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
    207 			return (1);
    208 		}
    209 
    210 		if (r & PCF_STAT_LRB) {
    211 			err = 1;
    212 			break;
    213 		}
    214 
    215 		if (i < len)
    216 			pcfiic_write(sc, PCF_S0, buf[i]);
    217 	}
    218 	pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
    219 	return (err);
    220 }
    221 
    222 int
    223 pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
    224 {
    225 	int			i = 0, err = 0;
    226 	volatile u_int8_t	r;
    227 
    228 	if (pcfiic_wait_nBB(sc) != 0)
    229 		return (1);
    230 
    231 	pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
    232 	pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
    233 
    234 	for (i = 0; i <= len; i++) {
    235 		if (pcfiic_wait_pin(sc, &r) != 0) {
    236 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
    237 			return (1);
    238 		}
    239 
    240 		if ((i != len) && (r & PCF_STAT_LRB)) {
    241 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
    242 			return (1);
    243 		}
    244 
    245 		if (i == len - 1) {
    246 			pcfiic_write(sc, PCF_S1, PCF_CTRL_ESO);
    247 		} else if (i == len) {
    248 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
    249 		}
    250 
    251 		r = pcfiic_read(sc, PCF_S0);
    252 		if (i > 0)
    253 			buf[i - 1] = r;
    254 	}
    255 	return (err);
    256 }
    257 
    258 u_int8_t
    259 pcfiic_read(struct pcfiic_softc *sc, bus_size_t r)
    260 {
    261 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
    262 	    BUS_SPACE_BARRIER_READ);
    263 	return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r]));
    264 }
    265 
    266 void
    267 pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v)
    268 {
    269 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v);
    270 	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, PCF_S1);
    271 }
    272 
    273 void
    274 pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus)
    275 {
    276 	bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus);
    277 	bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1,
    278 	    BUS_SPACE_BARRIER_WRITE);
    279 }
    280 
    281 int
    282 pcfiic_wait_nBB(struct pcfiic_softc *sc)
    283 {
    284 	int		i;
    285 
    286 	for (i = 0; i < 1000; i++) {
    287 		if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB)
    288 			return (0);
    289 		delay(1000);
    290 	}
    291 	return (1);
    292 }
    293 
    294 int
    295 pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
    296 {
    297 	int		i;
    298 
    299 	for (i = 0; i < 1000; i++) {
    300 		*r = pcfiic_read(sc, PCF_S1);
    301 		if ((*r & PCF_STAT_PIN) == 0)
    302 			return (0);
    303 		delay(1000);
    304 	}
    305 	return (1);
    306 }
    307