Annotation of sys/dev/ic/pcf8584.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pcf8584.c,v 1.8 2007/05/21 03:11:11 jsg Exp $ */
2:
3: /*
4: * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
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/malloc.h>
23: #include <sys/kernel.h>
24: #include <sys/rwlock.h>
25: #include <sys/proc.h>
26:
27: #include <machine/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: #define PCF_FREQ_90 0x00 /* 90 kHz */
64: #define PCF_FREQ_45 0x01 /* 45 kHz */
65: #define PCF_FREQ_11 0x02 /* 11 kHz */
66: #define PCF_FREQ_1_5 0x03 /* 1.5 kHz */
67:
68: struct cfdriver pcfiic_cd = {
69: NULL, "pcfiic", DV_DULL
70: };
71:
72: void pcfiic_init(struct pcfiic_softc *);
73: int pcfiic_i2c_acquire_bus(void *, int);
74: void pcfiic_i2c_release_bus(void *, int);
75: int pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
76: size_t, void *, size_t, int);
77:
78: int pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
79: size_t);
80: int pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
81: size_t);
82:
83: volatile u_int8_t pcfiic_read(struct pcfiic_softc *, bus_size_t);
84: volatile void pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
85: void pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t);
86: int pcfiic_wait_nBB(struct pcfiic_softc *);
87: int pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
88:
89: void
90: pcfiic_init(struct pcfiic_softc *sc)
91: {
92: /* init S1 */
93: pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
94: /* own address */
95: pcfiic_write(sc, PCF_S0, sc->sc_addr);
96:
97: /* select clock reg */
98: pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN|PCF_CTRL_ES1);
99: pcfiic_write(sc, PCF_S0, sc->sc_clock);
100:
101: pcfiic_write(sc, PCF_S1, PCF_CTRL_IDLE);
102:
103: delay(200000); /* Multi-Master mode, wait for longest i2c message */
104: }
105:
106: void
107: pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
108: int swapregs,
109: void (*scan_func)(struct device *, struct i2cbus_attach_args *, void *),
110: void *scan_arg)
111: {
112: struct i2cbus_attach_args iba;
113:
114: if (swapregs) {
115: sc->sc_regmap[PCF_S1] = PCF_S0;
116: sc->sc_regmap[PCF_S0] = PCF_S1;
117: } else {
118: sc->sc_regmap[PCF_S0] = PCF_S0;
119: sc->sc_regmap[PCF_S1] = PCF_S1;
120: }
121: sc->sc_clock = clock;
122: sc->sc_addr = addr;
123:
124: pcfiic_init(sc);
125:
126: printf("\n");
127:
128: if (sc->sc_master)
129: pcfiic_choose_bus(sc, 0);
130:
131: rw_init(&sc->sc_lock, "iiclk");
132: sc->sc_i2c.ic_cookie = sc;
133: sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus;
134: sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus;
135: sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
136:
137: bzero(&iba, sizeof(iba));
138: iba.iba_name = "iic";
139: iba.iba_tag = &sc->sc_i2c;
140: iba.iba_bus_scan = scan_func;
141: iba.iba_bus_scan_arg = scan_arg;
142: config_found(&sc->sc_dev, &iba, iicbus_print);
143: }
144:
145: int
146: pcfiic_intr(void *arg)
147: {
148: return (0);
149: }
150:
151: int
152: pcfiic_i2c_acquire_bus(void *arg, int flags)
153: {
154: struct pcfiic_softc *sc = arg;
155:
156: if (cold || sc->sc_poll || (flags & I2C_F_POLL))
157: return (0);
158:
159: return (rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR));
160: }
161:
162: void
163: pcfiic_i2c_release_bus(void *arg, int flags)
164: {
165: struct pcfiic_softc *sc = arg;
166:
167: if (cold || sc->sc_poll || (flags & I2C_F_POLL))
168: return;
169:
170: rw_exit(&sc->sc_lock);
171: }
172:
173: int
174: pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
175: const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
176: {
177: struct pcfiic_softc *sc = arg;
178: int ret = 0;
179:
180: #if 0
181: printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
182: sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags);
183: #endif
184:
185: if (cold || sc->sc_poll)
186: flags |= I2C_F_POLL;
187:
188: if (sc->sc_master)
189: pcfiic_choose_bus(sc, addr >> 7);
190:
191: if (cmdlen > 0)
192: if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0)
193: return (1);
194:
195: if (len > 0) {
196: if (I2C_OP_WRITE_P(op))
197: ret = pcfiic_xmit(sc, addr & 0x7f, buf, len);
198: else
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: volatile 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: volatile 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: bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
284: BUS_SPACE_BARRIER_WRITE);
285: }
286:
287: void
288: pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus)
289: {
290: bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus);
291: bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1,
292: BUS_SPACE_BARRIER_WRITE);
293: }
294:
295: int
296: pcfiic_wait_nBB(struct pcfiic_softc *sc)
297: {
298: int i;
299:
300: for (i = 0; i < 1000; i++) {
301: if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB)
302: return (0);
303: delay(1000);
304: }
305: return (1);
306: }
307:
308: int
309: pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
310: {
311: int i;
312:
313: for (i = 0; i < 1000; i++) {
314: *r = pcfiic_read(sc, PCF_S1);
315: if ((*r & PCF_STAT_PIN) == 0)
316: return (0);
317: delay(1000);
318: }
319: return (1);
320: }
CVSweb