1 /* $NetBSD: nslu2_iic.c,v 1.6 2008/06/09 15:42:25 tsutsui Exp $ */
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
36 #include <sys/mutex.h>
39 #include <dev/i2c/i2cvar.h>
40 #include <dev/i2c/i2c_bitbang.h>
42 #include <arm/xscale/ixp425reg.h>
43 #include <arm/xscale/ixp425var.h>
45 #include <evbarm/nslu2/nslu2reg.h>
47 struct slugiic_softc
{
49 struct i2c_controller sc_ic
;
50 struct i2c_bitbang_ops sc_ibo
;
56 slugiic_acquire_bus(void *arg
, int flags
)
58 struct slugiic_softc
*sc
= arg
;
60 if (flags
& I2C_F_POLL
)
63 mutex_enter(&sc
->sc_lock
);
68 slugiic_release_bus(void *arg
, int flags
)
70 struct slugiic_softc
*sc
= arg
;
72 if (flags
& I2C_F_POLL
)
75 mutex_exit(&sc
->sc_lock
);
79 slugiic_send_start(void *arg
, int flags
)
81 struct slugiic_softc
*sc
= arg
;
83 return (i2c_bitbang_send_start(sc
, flags
, &sc
->sc_ibo
));
87 slugiic_send_stop(void *arg
, int flags
)
89 struct slugiic_softc
*sc
= arg
;
91 return (i2c_bitbang_send_stop(sc
, flags
, &sc
->sc_ibo
));
95 slugiic_initiate_xfer(void *arg
, i2c_addr_t addr
, int flags
)
97 struct slugiic_softc
*sc
= arg
;
99 return (i2c_bitbang_initiate_xfer(sc
, addr
, flags
, &sc
->sc_ibo
));
103 slugiic_read_byte(void *arg
, uint8_t *vp
, int flags
)
105 struct slugiic_softc
*sc
= arg
;
107 return (i2c_bitbang_read_byte(sc
, vp
, flags
, &sc
->sc_ibo
));
111 slugiic_write_byte(void *arg
, uint8_t v
, int flags
)
113 struct slugiic_softc
*sc
= arg
;
115 return (i2c_bitbang_write_byte(sc
, v
, flags
, &sc
->sc_ibo
));
119 slugiic_set_dir(void *arg
, uint32_t bits
)
121 struct slugiic_softc
*sc
= arg
;
125 if (sc
->sc_dirout
== bits
)
130 sc
->sc_dirout
= bits
;
133 /* SDA is output; enable SDA output if SDA OUTR is low */
134 reg
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPOUTR
);
135 if ((reg
& GPIO_I2C_SDA_BIT
) == 0) {
136 reg
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPOER
);
137 reg
&= ~GPIO_I2C_SDA_BIT
;
138 GPIO_CONF_WRITE_4(ixp425_softc
, IXP425_GPIO_GPOER
, reg
);
141 /* SDA is input; disable SDA output */
142 reg
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPOER
);
143 reg
|= GPIO_I2C_SDA_BIT
;
144 GPIO_CONF_WRITE_4(ixp425_softc
, IXP425_GPIO_GPOER
, reg
);
151 slugiic_set_bits(void *arg
, uint32_t bits
)
153 struct slugiic_softc
*sc
= arg
;
160 * Enable SCL output if the SCL line is to be driven low.
161 * Enable SDA output if the SDA line is to be driven low and
162 * SDA direction is output.
163 * Otherwise switch them to input even if directions are output
164 * so that we can emulate open collector output with the pullup
166 * If lines are to be set to high, disable OER first then set OUTR.
167 * If lines are to be set to low, set OUTR first then enable OER.
169 oer
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPOER
);
170 if ((bits
& GPIO_I2C_SCL_BIT
) != 0)
171 oer
|= GPIO_I2C_SCL_BIT
;
172 if ((bits
& GPIO_I2C_SDA_BIT
) != 0)
173 oer
|= GPIO_I2C_SDA_BIT
;
174 GPIO_CONF_WRITE_4(ixp425_softc
, IXP425_GPIO_GPOER
, oer
);
176 outr
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPOUTR
);
177 outr
&= ~(GPIO_I2C_SDA_BIT
| GPIO_I2C_SCL_BIT
);
178 GPIO_CONF_WRITE_4(ixp425_softc
, IXP425_GPIO_GPOUTR
, outr
| bits
);
180 if ((bits
& GPIO_I2C_SCL_BIT
) == 0)
181 oer
&= ~GPIO_I2C_SCL_BIT
;
182 if ((bits
& GPIO_I2C_SDA_BIT
) == 0 && sc
->sc_dirout
)
183 oer
&= ~GPIO_I2C_SDA_BIT
;
184 GPIO_CONF_WRITE_4(ixp425_softc
, IXP425_GPIO_GPOER
, oer
);
190 slugiic_read_bits(void *arg
)
194 reg
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPINR
);
195 return (reg
& (GPIO_I2C_SDA_BIT
| GPIO_I2C_SCL_BIT
));
199 slugiic_deferred_attach(struct device
*device
)
201 struct slugiic_softc
*sc
= (struct slugiic_softc
*)device
;
202 struct i2cbus_attach_args iba
;
205 reg
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPOUTR
);
206 reg
|= GPIO_I2C_SDA_BIT
| GPIO_I2C_SCL_BIT
;
207 GPIO_CONF_WRITE_4(ixp425_softc
, IXP425_GPIO_GPOUTR
, reg
);
209 reg
= GPIO_CONF_READ_4(ixp425_softc
, IXP425_GPIO_GPOER
);
210 reg
&= ~GPIO_I2C_SCL_BIT
;
211 reg
|= GPIO_I2C_SDA_BIT
;
212 GPIO_CONF_WRITE_4(ixp425_softc
, IXP425_GPIO_GPOER
, reg
);
214 iba
.iba_tag
= &sc
->sc_ic
;
215 (void) config_found_ia(&sc
->sc_dev
, "i2cbus", &iba
, iicbus_print
);
219 slugiic_match(struct device
*parent
, struct cfdata
*cf
, void *arg
)
226 slugiic_attach(struct device
*parent
, struct device
*self
, void *arg
)
228 struct slugiic_softc
*sc
= (struct slugiic_softc
*)self
;
231 aprint_normal(": I2C bus\n");
233 sc
->sc_ic
.ic_cookie
= sc
;
234 sc
->sc_ic
.ic_acquire_bus
= slugiic_acquire_bus
;
235 sc
->sc_ic
.ic_release_bus
= slugiic_release_bus
;
236 sc
->sc_ic
.ic_exec
= NULL
;
237 sc
->sc_ic
.ic_send_start
= slugiic_send_start
;
238 sc
->sc_ic
.ic_send_stop
= slugiic_send_stop
;
239 sc
->sc_ic
.ic_initiate_xfer
= slugiic_initiate_xfer
;
240 sc
->sc_ic
.ic_read_byte
= slugiic_read_byte
;
241 sc
->sc_ic
.ic_write_byte
= slugiic_write_byte
;
243 sc
->sc_ibo
.ibo_set_dir
= slugiic_set_dir
;
244 sc
->sc_ibo
.ibo_set_bits
= slugiic_set_bits
;
245 sc
->sc_ibo
.ibo_read_bits
= slugiic_read_bits
;
246 sc
->sc_ibo
.ibo_bits
[I2C_BIT_SDA
] = GPIO_I2C_SDA_BIT
;
247 sc
->sc_ibo
.ibo_bits
[I2C_BIT_SCL
] = GPIO_I2C_SCL_BIT
;
248 sc
->sc_ibo
.ibo_bits
[I2C_BIT_OUTPUT
] = 1;
249 sc
->sc_ibo
.ibo_bits
[I2C_BIT_INPUT
] = 0;
251 mutex_init(&sc
->sc_lock
, MUTEX_DEFAULT
, IPL_NONE
);
256 * Defer until ixp425_softc has been initialised
258 config_interrupts(self
, slugiic_deferred_attach
);
261 CFATTACH_DECL(slugiic
, sizeof(struct slugiic_softc
),
262 slugiic_match
, slugiic_attach
, NULL
, NULL
);