1 /* $Id: at91twi.c,v 1.4 2009/03/14 21:04:05 dsl Exp $ */
2 /* $NetBSD: at91twi.c,v 1.3 2009/03/14 15:36:01 dsl Exp $ */
5 * Copyright (c) 2007 Embedtronics Oy. All rights reserved.
7 * Based on arch/macppc/dev/ki2c.c,
8 * Copyright (c) 2001 Tsubai Masanari. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: at91twi.c,v 1.3 2009/03/14 15:36:01 dsl Exp $");
36 #include <sys/param.h>
37 #include <sys/device.h>
38 #include <sys/systm.h>
40 #include <machine/bus.h>
43 #include <arm/at91/at91var.h>
44 #include <arm/at91/at91reg.h>
46 #include <dev/i2c/i2cvar.h>
47 #include <arm/at91/at91twivar.h>
48 #include <arm/at91/at91twireg.h>
50 int at91twi_match(device_t
, cfdata_t
, void *);
51 void at91twi_attach(device_t
, device_t
, void *);
52 inline u_int
at91twi_readreg(struct at91twi_softc
*, int);
53 inline void at91twi_writereg(struct at91twi_softc
*, int, u_int
);
54 int at91twi_intr(void *);
55 int at91twi_poll(struct at91twi_softc
*, int, int);
56 int at91twi_start(struct at91twi_softc
*, int, void *, int, int);
57 int at91twi_read(struct at91twi_softc
*, int, void *, int, int);
58 int at91twi_write(struct at91twi_softc
*, int, void *, int, int);
61 static int at91twi_i2c_acquire_bus(void *, int);
62 static void at91twi_i2c_release_bus(void *, int);
63 static int at91twi_i2c_exec(void *, i2c_op_t
, i2c_addr_t
, const void *, size_t,
67 CFATTACH_DECL_NEW(at91twi
, sizeof(struct at91twi_softc
),
68 at91twi_match
, at91twi_attach
, NULL
, NULL
);
71 at91twi_match(device_t parent
, cfdata_t match
, void *aux
)
73 if (strcmp(match
->cf_name
, "at91twi") == 0)
79 at91twi_attach(device_t parent
, device_t self
, void *aux
)
81 struct at91twi_softc
*sc
= device_private(self
);
82 struct at91bus_attach_args
*sa
= aux
;
83 struct i2cbus_attach_args iba
;
84 unsigned ckdiv
, cxdiv
;
86 // gather attach data:
88 sc
->sc_iot
= sa
->sa_iot
;
89 sc
->sc_pid
= sa
->sa_pid
;
91 if (bus_space_map(sa
->sa_iot
, sa
->sa_addr
, sa
->sa_size
, 0, &sc
->sc_ioh
))
92 panic("%s: Cannot map registers", self
->dv_xname
);
94 printf(": I2C controller\n");
96 /* initialize I2C controller */
97 at91_peripheral_clock(sc
->sc_pid
, 1);
99 at91twi_writereg(sc
, TWI_CR
, TWI_CR_SWRST
);
103 for (ckdiv
= 0; ckdiv
< 8; ckdiv
++) {
104 if ((cxdiv
= (AT91_MSTCLK
/ (1U << ckdiv
)) / (2 * 50000U)) < 256) {
108 panic("%s: Cannot calculate clock divider!", __FUNCTION__
);
112 ckdiv
= 5; cxdiv
= 0xFF;
114 at91twi_writereg(sc
, TWI_CWGR
, (ckdiv
<< 16) | (cxdiv
<< 8) | cxdiv
);
115 at91twi_writereg(sc
, TWI_CR
, TWI_CR_MSEN
);
117 //#ifdef AT91TWI_DEBUG
118 printf("%s: ckdiv=%d cxdiv=%d CWGR=0x%08X SR=0x%08X\n", self
->dv_xname
, ckdiv
, cxdiv
, at91twi_readreg(sc
, TWI_CWGR
), at91twi_readreg(sc
, TWI_SR
));
121 /* initialize rest */
122 mutex_init(&sc
->sc_buslock
, MUTEX_DEFAULT
, IPL_NONE
);
123 sc
->sc_ih
= at91_intr_establish(sc
->sc_pid
, IPL_SERIAL
, INTR_HIGH_LEVEL
,
126 /* fill in the i2c tag */
127 sc
->sc_i2c
.ic_cookie
= sc
;
128 sc
->sc_i2c
.ic_acquire_bus
= at91twi_i2c_acquire_bus
;
129 sc
->sc_i2c
.ic_release_bus
= at91twi_i2c_release_bus
;
130 sc
->sc_i2c
.ic_send_start
= NULL
;
131 sc
->sc_i2c
.ic_send_stop
= NULL
;
132 sc
->sc_i2c
.ic_initiate_xfer
= NULL
;
133 sc
->sc_i2c
.ic_read_byte
= NULL
;
134 sc
->sc_i2c
.ic_write_byte
= NULL
;
135 sc
->sc_i2c
.ic_exec
= at91twi_i2c_exec
;
137 iba
.iba_tag
= &sc
->sc_i2c
;
138 (void) config_found_ia(sc
->sc_dev
, "i2cbus", &iba
, iicbus_print
);
142 at91twi_readreg(struct at91twi_softc
*sc
, int reg
)
144 return bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, reg
);
148 at91twi_writereg(struct at91twi_softc
*sc
, int reg
, u_int val
)
150 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, reg
, val
);
154 at91twi_intr(void *arg
)
156 struct at91twi_softc
*sc
= arg
;
159 sr
= at91twi_readreg(sc
, TWI_SR
);
160 imr
= at91twi_readreg(sc
, TWI_IMR
);
165 // printf("%s(%s): interrupts are disabled (sr=%08X imr=%08X)\n", __FUNCTION__, device_xname(sc->sc_dev), sr, imr);
170 if (isr
& TWI_SR_TXCOMP
) {
171 // transmission has completed!
172 if (sr
& (TWI_SR_NACK
| TWI_SR_UNRE
| TWI_SR_OVRE
)) {
175 printf("%s(%s): FAILED (sr=%08X)\n", __FUNCTION__
,
176 device_xname(sc
->sc_dev
), sr
);
178 sc
->sc_flags
|= I2C_ERROR
;
181 printf("%s(%s): SUCCESS (sr=%08X)\n", __FUNCTION__
,
182 device_xname(sc
->sc_dev
), sr
);
185 if (sc
->sc_flags
& I2C_READING
&& sr
& TWI_SR_RXRDY
) {
186 *sc
->sc_data
++ = at91twi_readreg(sc
, TWI_RHR
);
189 sc
->sc_flags
&= ~I2C_BUSY
;
190 at91twi_writereg(sc
, TWI_IDR
, -1);
194 if (isr
& TWI_SR_TXRDY
) {
195 if (--sc
->sc_resid
> 0)
196 at91twi_writereg(sc
, TWI_THR
, *sc
->sc_data
++);
199 if (isr
& TWI_SR_RXRDY
) {
200 // data has been received
201 *sc
->sc_data
++ = at91twi_readreg(sc
, TWI_RHR
);
205 if (isr
& (TWI_SR_TXRDY
| TWI_SR_RXRDY
) && sc
->sc_resid
<= 0) {
206 // all bytes have been transmitted, send stop condition
207 at91twi_writereg(sc
, TWI_IDR
, TWI_SR_RXRDY
| TWI_SR_TXRDY
);
208 at91twi_writereg(sc
, TWI_CR
, TWI_CR_STOP
);
215 at91twi_poll(struct at91twi_softc
*sc
, int timo
, int flags
)
220 while (sc
->sc_flags
& I2C_BUSY
) {
222 printf("i2c_poll: timeout\n");
225 if (flags
& I2C_F_POLL
) {
226 at91_intr_poll(sc
->sc_ih
, 1);
230 delay(100); // @@@ sleep!?
238 at91twi_start(struct at91twi_softc
*sc
, int addr
, void *data
, int len
,
241 int rd
= (sc
->sc_flags
& I2C_READING
);
244 KASSERT((addr
& 1) == 0);
248 sc
->sc_flags
|= I2C_BUSY
;
250 timo
= 1000 + len
* 200;
253 // if writing, queue first byte immediately
255 at91twi_writereg(sc
, TWI_THR
, *sc
->sc_data
++);
256 // if there's just one byte to transmit, we must set STOP-bit too
257 if (sc
->sc_resid
== 1) {
258 at91twi_writereg(sc
, TWI_IER
, TWI_SR_TXCOMP
);
259 at91twi_writereg(sc
, TWI_CR
, TWI_CR_START
| TWI_CR_STOP
);
261 at91twi_writereg(sc
, TWI_IER
, TWI_SR_TXCOMP
262 | (rd
? TWI_SR_RXRDY
: TWI_SR_TXRDY
));
263 at91twi_writereg(sc
, TWI_CR
, TWI_CR_START
);
267 if (at91twi_poll(sc
, timo
, flags
))
269 if (sc
->sc_flags
& I2C_ERROR
) {
270 printf("I2C_ERROR\n");
277 at91twi_read(struct at91twi_softc
*sc
, int addr
, void *data
, int len
, int flags
)
279 sc
->sc_flags
= I2C_READING
;
281 printf("at91twi_read: %02x %d\n", addr
, len
);
283 return at91twi_start(sc
, addr
, data
, len
, flags
);
287 at91twi_write(struct at91twi_softc
*sc
, int addr
, void *data
, int len
, int flags
)
291 printf("at91twi_write: %02x %d\n", addr
, len
);
293 return at91twi_start(sc
, addr
, data
, len
, flags
);
297 at91twi_i2c_acquire_bus(void *cookie
, int flags
)
299 struct at91twi_softc
*sc
= cookie
;
301 if (flags
& I2C_F_POLL
)
304 mutex_enter(&sc
->sc_buslock
);
309 at91twi_i2c_release_bus(void *cookie
, int flags
)
311 struct at91twi_softc
*sc
= cookie
;
313 if (flags
& I2C_F_POLL
)
316 mutex_exit(&sc
->sc_buslock
);
320 at91twi_i2c_exec(void *cookie
, i2c_op_t op
, i2c_addr_t addr
, const void *vcmd
,
321 size_t cmdlen
, void *vbuf
, size_t buflen
, int flags
)
323 struct at91twi_softc
*sc
= cookie
;
325 if (I2C_OP_READ_P(op
))
329 const uint8_t *cmd
= (const uint8_t *)vcmd
;
331 // we're in trouble..
344 at91twi_writereg(sc
, TWI_MMR
, (addr
<< 16) | TWI_MMR_MREAD
| (cmdlen
<< 8));
347 printf("at91twi_read: %02x iadr=%08X mmr=%08X\n",
348 addr
, iadr
, at91twi_readreg(sc
, TWI_MMR
));
350 at91twi_writereg(sc
, TWI_IADR
, iadr
);
352 if (at91twi_read(sc
, addr
, vbuf
, buflen
, flags
) != 0)
355 at91twi_writereg(sc
, TWI_MMR
, addr
<< 16);
356 if (at91twi_write(sc
, addr
, __UNCONST(vcmd
), cmdlen
, flags
) !=0)