xref: /netbsd-src/sys/dev/ic/pcf8584.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: pcf8584.c,v 1.11 2014/01/20 22:02:32 jdc 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@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 (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0)
179 		return (1);
180 
181 	if (len > 0) {
182 		if (I2C_OP_WRITE_P(op))
183 			ret = pcfiic_xmit(sc, addr & 0x7f, buf, len);
184 		else
185 			ret = pcfiic_recv(sc, addr & 0x7f, buf, len);
186 	}
187 	return (ret);
188 }
189 
190 int
191 pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
192     size_t len)
193 {
194 	int			i, err = 0;
195 	volatile u_int8_t	r;
196 
197 	if (pcfiic_wait_nBB(sc) != 0)
198 		return (1);
199 
200 	pcfiic_write(sc, PCF_S0, addr << 1);
201 	pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
202 
203 	for (i = 0; i <= len; i++) {
204 		if (pcfiic_wait_pin(sc, &r) != 0) {
205 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
206 			return (1);
207 		}
208 
209 		if (r & PCF_STAT_LRB) {
210 			err = 1;
211 			break;
212 		}
213 
214 		if (i < len)
215 			pcfiic_write(sc, PCF_S0, buf[i]);
216 	}
217 	pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
218 	return (err);
219 }
220 
221 int
222 pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
223 {
224 	int			i = 0, err = 0;
225 	volatile u_int8_t	r;
226 
227 	if (pcfiic_wait_nBB(sc) != 0)
228 		return (1);
229 
230 	pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
231 	pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
232 
233 	for (i = 0; i <= len; i++) {
234 		if (pcfiic_wait_pin(sc, &r) != 0) {
235 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
236 			return (1);
237 		}
238 
239 		if ((i != len) && (r & PCF_STAT_LRB)) {
240 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
241 			return (1);
242 		}
243 
244 		if (i == len - 1) {
245 			pcfiic_write(sc, PCF_S1, PCF_CTRL_ESO);
246 		} else if (i == len) {
247 			pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
248 		}
249 
250 		r = pcfiic_read(sc, PCF_S0);
251 		if (i > 0)
252 			buf[i - 1] = r;
253 	}
254 	return (err);
255 }
256 
257 u_int8_t
258 pcfiic_read(struct pcfiic_softc *sc, bus_size_t r)
259 {
260 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
261 	    BUS_SPACE_BARRIER_READ);
262 	return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r]));
263 }
264 
265 void
266 pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v)
267 {
268 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v);
269 	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, PCF_S1);
270 }
271 
272 void
273 pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus)
274 {
275 	bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus);
276 	bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1,
277 	    BUS_SPACE_BARRIER_WRITE);
278 }
279 
280 int
281 pcfiic_wait_nBB(struct pcfiic_softc *sc)
282 {
283 	int		i;
284 
285 	for (i = 0; i < 1000; i++) {
286 		if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB)
287 			return (0);
288 		delay(1000);
289 	}
290 	return (1);
291 }
292 
293 int
294 pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
295 {
296 	int		i;
297 
298 	for (i = 0; i < 1000; i++) {
299 		*r = pcfiic_read(sc, PCF_S1);
300 		if ((*r & PCF_STAT_PIN) == 0)
301 			return (0);
302 		delay(1000);
303 	}
304 	return (1);
305 }
306