pcf8584.c revision 1.12
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
63void		pcfiic_init(struct pcfiic_softc *);
64int		pcfiic_i2c_acquire_bus(void *, int);
65void		pcfiic_i2c_release_bus(void *, int);
66int		pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
67		    size_t, void *, size_t, int);
68
69int		pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
70		    size_t);
71int		pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
72		    size_t);
73
74u_int8_t	pcfiic_read(struct pcfiic_softc *, bus_size_t);
75void		pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
76void		pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t);
77int		pcfiic_wait_nBB(struct pcfiic_softc *);
78int		pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
79
80void
81pcfiic_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
97void
98pcfiic_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
131int
132pcfiic_intr(void *arg)
133{
134	return (0);
135}
136
137int
138pcfiic_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
149void
150pcfiic_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
160int
161pcfiic_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
204int
205pcfiic_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
235int
236pcfiic_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
271u_int8_t
272pcfiic_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
279void
280pcfiic_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
286void
287pcfiic_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
294int
295pcfiic_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
307int
308pcfiic_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