Sync usage with man page.
[netbsd-mini2440.git] / sys / dev / marvell / gti2c.c
blobe22c45977b1134d09637f73ae96682b27c8b47c0
1 /* $NetBSD: gti2c.c,v 1.11 2009/05/12 12:18:45 cegger Exp $ */
3 /*
4 * Copyright (c) 2005 Brocade Communcations, inc.
5 * All rights reserved.
7 * Written by Matt Thomas for Brocade Communcations, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Brocade Communications, Inc. may not be used to endorse
18 * or promote products derived from this software without specific prior
19 * written permission.
21 * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: gti2c.c,v 1.11 2009/05/12 12:18:45 cegger Exp $");
37 #include <sys/param.h>
38 #include <sys/device.h>
39 #include <sys/conf.h>
40 #include <sys/proc.h>
41 #include <sys/mutex.h>
42 #include <sys/intr.h>
43 #include <sys/bus.h>
45 #include <dev/marvell/gtintrreg.h>
46 #include <dev/marvell/gti2creg.h>
48 #include <dev/marvell/gtvar.h>
50 #include <dev/i2c/i2cvar.h>
52 struct gti2c_softc {
53 struct device sc_dev;
54 struct evcnt sc_ev_intr;
55 struct i2c_controller sc_i2c;
56 struct gt_softc *sc_gt;
57 kmutex_t sc_lock;
60 static int gt_i2c_match(device_t, cfdata_t, void *);
61 static void gt_i2c_attach(device_t, device_t, void *);
63 CFATTACH_DECL(gtiic, sizeof(struct gti2c_softc),
64 gt_i2c_match, gt_i2c_attach, NULL, NULL);
66 extern struct cfdriver gtiic_cd;
68 static int
69 gt_i2c_wait(struct gti2c_softc *sc, uint32_t control,
70 uint32_t desired_status, int flags)
72 uint32_t status;
73 int error = 0;
75 again:
76 if (flags & I2C_F_POLL)
77 control |= I2C_Control_IntEn;
78 if (desired_status != I2C_Status_MasterReadAck)
79 gt_write(sc->sc_gt, I2C_REG_Control, control);
81 for (;;) {
82 control = gt_read(sc->sc_gt, I2C_REG_Control);
83 if (control & I2C_Control_IFlg)
84 break;
85 error = tsleep(sc, PZERO, "gti2cwait",
86 (flags & I2C_F_POLL) ? 1 : 0);
87 if (error && (error != ETIMEDOUT || !(flags & I2C_F_POLL)))
88 return error;
91 status = gt_read(sc->sc_gt, I2C_REG_Status);
92 if (status != desired_status)
93 return EIO;
95 if ((flags & I2C_F_LAST) &&
96 desired_status != I2C_Status_MasterReadAck) {
97 control = I2C_Control_Stop;
98 goto again;
101 return error;
104 static int
105 gt_i2c_acquire_bus(void *cookie, int flags)
107 struct gti2c_softc * const sc = cookie;
108 uint32_t status;
110 if (flags & I2C_F_POLL)
111 return 0;
113 mutex_enter(&sc->sc_lock);
114 status = gt_read(sc->sc_gt, I2C_REG_Status);
115 if (status != I2C_Status_Idle) {
116 gt_write(sc->sc_gt, I2C_REG_SoftReset, 1);
119 return 0;
122 static void
123 gt_i2c_release_bus(void *cookie, int flags)
125 struct gti2c_softc * const sc = cookie;
127 mutex_exit(&sc->sc_lock);
130 static int
131 gt_i2c_send_start(void *cookie, int flags)
133 struct gti2c_softc * const sc = cookie;
135 return gt_i2c_wait(sc, I2C_Control_Start, I2C_Status_Started, flags);
138 static int
139 gt_i2c_send_stop(void *cookie, int flags)
141 struct gti2c_softc * const sc = cookie;
143 return gt_i2c_wait(sc, I2C_Control_Stop, I2C_Status_Idle, flags);
146 static int
147 gt_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
149 struct gti2c_softc * const sc = cookie;
150 uint32_t data, wanted_status;
151 uint8_t read_mask = (flags & I2C_F_READ) != 0;
152 int error;
154 if (read_mask) {
155 wanted_status = I2C_Status_AddrReadAck;
156 } else {
157 wanted_status = I2C_Status_AddrWriteAck;
160 * First byte contains whether this xfer is a read or write.
162 data = read_mask;
163 if (addr > 0x7f) {
165 * If this is a 10bit request, the first address byte is
166 * 0b11110<b9><b8><r/w>.
168 data |= 0xf0 | ((addr & 0x30) >> 7);
169 gt_write(sc->sc_gt, I2C_REG_Data, data);
170 error = gt_i2c_wait(sc, 0, wanted_status, flags);
171 if (error)
172 return error;
174 * The first address byte has been sent, now to send
175 * the second one.
177 if (read_mask) {
178 wanted_status = I2C_Status_2ndAddrReadAck;
179 } else {
180 wanted_status = I2C_Status_2ndAddrWriteAck;
182 data = (uint8_t) addr;
183 } else {
184 data |= (addr << 1);
187 gt_write(sc->sc_gt, I2C_REG_Data, data);
188 return gt_i2c_wait(sc, 0, wanted_status, flags);
191 static int
192 gt_i2c_read_byte(void *cookie, uint8_t *dp, int flags)
194 struct gti2c_softc * const sc = cookie;
195 int error;
197 gt_write(sc->sc_gt, I2C_REG_Data, *dp);
198 error = gt_i2c_wait(sc, 0, I2C_Status_MasterReadAck, flags);
199 if (error == 0) {
200 *dp = gt_read(sc->sc_gt, I2C_REG_Data);
202 if (flags & I2C_F_LAST)
203 gt_write(sc->sc_gt, I2C_REG_Control, 0);
204 return error;
207 static int
208 gt_i2c_write_byte(void *cookie, uint8_t v, int flags)
210 struct gti2c_softc * const sc = cookie;
212 gt_write(sc->sc_gt, I2C_REG_Data, v);
213 return gt_i2c_wait(sc, 0, I2C_Status_MasterWriteAck, flags);
216 static int
217 gt_i2c_intr(void *aux)
219 struct gti2c_softc * const sc = aux;
220 uint32_t v;
222 v = gt_read(sc->sc_gt, I2C_REG_Control);
223 if ((v & I2C_Control_IFlg) == 0)
224 return 0;
225 gt_write(sc->sc_gt, I2C_REG_Control, v & ~I2C_Control_IntEn);
227 sc->sc_ev_intr.ev_count++;
229 wakeup(sc);
230 return 1;
234 gt_i2c_match(device_t parent, cfdata_t cfdata, void *aux)
236 struct gt_softc * const gt = device_private(parent);
237 struct gt_attach_args * const ga = aux;
239 return GT_I2COK(gt, ga, &gtiic_cd);
242 void
243 gt_i2c_attach(device_t parent, device_t self, void *aux)
245 struct gt_softc * const gt = device_private(parent);
246 struct gti2c_softc * const sc = device_private(self);
247 struct gt_attach_args * const ga = aux;
248 struct i2cbus_attach_args iba;
250 sc->sc_gt = gt;
252 GT_I2CFOUND(gt, ga);
254 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
256 sc->sc_i2c.ic_cookie = sc;
257 sc->sc_i2c.ic_acquire_bus = gt_i2c_acquire_bus;
258 sc->sc_i2c.ic_release_bus = gt_i2c_release_bus;
259 sc->sc_i2c.ic_release_bus = gt_i2c_release_bus;
260 sc->sc_i2c.ic_send_start = gt_i2c_send_start;
261 sc->sc_i2c.ic_send_stop = gt_i2c_send_stop;
262 sc->sc_i2c.ic_initiate_xfer = gt_i2c_initiate_xfer;
263 sc->sc_i2c.ic_read_byte = gt_i2c_read_byte;
264 sc->sc_i2c.ic_write_byte = gt_i2c_write_byte;
266 intr_establish(IRQ_I2C, IST_LEVEL, IPL_VM, gt_i2c_intr, sc);
268 evcnt_attach_dynamic(&sc->sc_ev_intr, EVCNT_TYPE_INTR, NULL,
269 device_xname(&sc->sc_dev), "intr");
271 iba.iba_tag = &sc->sc_i2c;
272 config_found_ia(self, "i2cbus", &iba, iicbus_print);