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