This source file includes following definitions.
- pcfiic_init
- pcfiic_attach
- pcfiic_intr
- pcfiic_i2c_acquire_bus
- pcfiic_i2c_release_bus
- pcfiic_i2c_exec
- pcfiic_xmit
- pcfiic_recv
- pcfiic_read
- pcfiic_write
- pcfiic_choose_bus
- pcfiic_wait_nBB
- pcfiic_wait_pin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
64 #define PCF_FREQ_45 0x01
65 #define PCF_FREQ_11 0x02
66 #define PCF_FREQ_1_5 0x03
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
93 pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
94
95 pcfiic_write(sc, PCF_S0, sc->sc_addr);
96
97
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);
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 }