xref: /freebsd/sys/arm/freescale/imx/imx_i2c.c (revision 40d7d6323be8be3788c270f26cccecd1e552e4ca)
1484b4fd4SRuslan Bukin /*-
2484b4fd4SRuslan Bukin  * Copyright (C) 2008-2009 Semihalf, Michal Hajduk
3484b4fd4SRuslan Bukin  * Copyright (c) 2012, 2013 The FreeBSD Foundation
4484b4fd4SRuslan Bukin  * All rights reserved.
5484b4fd4SRuslan Bukin  *
6484b4fd4SRuslan Bukin  * Portions of this software were developed by Oleksandr Rybalko
7484b4fd4SRuslan Bukin  * under sponsorship from the FreeBSD Foundation.
8484b4fd4SRuslan Bukin  *
9484b4fd4SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
10484b4fd4SRuslan Bukin  * modification, are permitted provided that the following conditions
11484b4fd4SRuslan Bukin  * are met:
12484b4fd4SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
13484b4fd4SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
14484b4fd4SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
15484b4fd4SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
16484b4fd4SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
17484b4fd4SRuslan Bukin  *
18484b4fd4SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19484b4fd4SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20484b4fd4SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21484b4fd4SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22484b4fd4SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23484b4fd4SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24484b4fd4SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25484b4fd4SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26484b4fd4SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27484b4fd4SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28484b4fd4SRuslan Bukin  * SUCH DAMAGE.
29484b4fd4SRuslan Bukin  */
30484b4fd4SRuslan Bukin 
31484b4fd4SRuslan Bukin #include <sys/cdefs.h>
32484b4fd4SRuslan Bukin __FBSDID("$FreeBSD$");
33484b4fd4SRuslan Bukin 
34484b4fd4SRuslan Bukin #include <sys/param.h>
35484b4fd4SRuslan Bukin #include <sys/systm.h>
36484b4fd4SRuslan Bukin #include <sys/bus.h>
37484b4fd4SRuslan Bukin #include <sys/kernel.h>
38484b4fd4SRuslan Bukin #include <sys/module.h>
39484b4fd4SRuslan Bukin #include <sys/resource.h>
40484b4fd4SRuslan Bukin 
41484b4fd4SRuslan Bukin #include <machine/bus.h>
42484b4fd4SRuslan Bukin #include <machine/resource.h>
43484b4fd4SRuslan Bukin #include <sys/rman.h>
44484b4fd4SRuslan Bukin 
45484b4fd4SRuslan Bukin #include <sys/lock.h>
46484b4fd4SRuslan Bukin #include <sys/mutex.h>
47484b4fd4SRuslan Bukin 
48484b4fd4SRuslan Bukin #include <dev/iicbus/iiconf.h>
49484b4fd4SRuslan Bukin #include <dev/iicbus/iicbus.h>
50484b4fd4SRuslan Bukin #include "iicbus_if.h"
51484b4fd4SRuslan Bukin 
52484b4fd4SRuslan Bukin #include <dev/fdt/fdt_common.h>
53484b4fd4SRuslan Bukin #include <dev/ofw/openfirm.h>
54484b4fd4SRuslan Bukin #include <dev/ofw/ofw_bus.h>
55484b4fd4SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
56484b4fd4SRuslan Bukin 
57484b4fd4SRuslan Bukin #define I2C_ADDR_REG		0x00 /* I2C slave address register */
58484b4fd4SRuslan Bukin #define I2C_FDR_REG		0x04 /* I2C frequency divider register */
59484b4fd4SRuslan Bukin #define I2C_CONTROL_REG		0x08 /* I2C control register */
60484b4fd4SRuslan Bukin #define I2C_STATUS_REG		0x0C /* I2C status register */
61484b4fd4SRuslan Bukin #define I2C_DATA_REG		0x10 /* I2C data register */
62484b4fd4SRuslan Bukin #define I2C_DFSRR_REG		0x14 /* I2C Digital Filter Sampling rate */
63484b4fd4SRuslan Bukin 
64484b4fd4SRuslan Bukin #define I2CCR_MEN		(1 << 7) /* Module enable */
65484b4fd4SRuslan Bukin #define I2CCR_MSTA		(1 << 5) /* Master/slave mode */
66484b4fd4SRuslan Bukin #define I2CCR_MTX		(1 << 4) /* Transmit/receive mode */
67484b4fd4SRuslan Bukin #define I2CCR_TXAK		(1 << 3) /* Transfer acknowledge */
68484b4fd4SRuslan Bukin #define I2CCR_RSTA		(1 << 2) /* Repeated START */
69484b4fd4SRuslan Bukin 
70484b4fd4SRuslan Bukin #define I2CSR_MCF		(1 << 7) /* Data transfer */
71484b4fd4SRuslan Bukin #define I2CSR_MASS		(1 << 6) /* Addressed as a slave */
72484b4fd4SRuslan Bukin #define I2CSR_MBB		(1 << 5) /* Bus busy */
73484b4fd4SRuslan Bukin #define I2CSR_MAL		(1 << 4) /* Arbitration lost */
74484b4fd4SRuslan Bukin #define I2CSR_SRW		(1 << 2) /* Slave read/write */
75484b4fd4SRuslan Bukin #define I2CSR_MIF		(1 << 1) /* Module interrupt */
76484b4fd4SRuslan Bukin #define I2CSR_RXAK		(1 << 0) /* Received acknowledge */
77484b4fd4SRuslan Bukin 
78484b4fd4SRuslan Bukin #define I2C_BAUD_RATE_FAST	0x31
79484b4fd4SRuslan Bukin #define I2C_BAUD_RATE_DEF	0x3F
80484b4fd4SRuslan Bukin #define I2C_DFSSR_DIV		0x10
81484b4fd4SRuslan Bukin 
82484b4fd4SRuslan Bukin #ifdef  DEBUG
83484b4fd4SRuslan Bukin #define debugf(fmt, args...) do { printf("%s(): ", __func__);		\
84484b4fd4SRuslan Bukin 		printf(fmt,##args); } while (0)
85484b4fd4SRuslan Bukin #else
86484b4fd4SRuslan Bukin #define debugf(fmt, args...)
87484b4fd4SRuslan Bukin #endif
88484b4fd4SRuslan Bukin 
89*40d7d632SRuslan Bukin static struct ofw_compat_data compat_data[] = {
90*40d7d632SRuslan Bukin 	{"fsl,imx6q-i2c",  1},
91*40d7d632SRuslan Bukin 	{"fsl,imx-i2c",	   1},
92*40d7d632SRuslan Bukin 	{NULL,             0}
93*40d7d632SRuslan Bukin };
94*40d7d632SRuslan Bukin 
95484b4fd4SRuslan Bukin struct i2c_softc {
96484b4fd4SRuslan Bukin 	device_t		dev;
97484b4fd4SRuslan Bukin 	device_t		iicbus;
98484b4fd4SRuslan Bukin 	struct resource		*res;
99484b4fd4SRuslan Bukin 	struct mtx		mutex;
100484b4fd4SRuslan Bukin 	int			rid;
101484b4fd4SRuslan Bukin 	bus_space_handle_t	bsh;
102484b4fd4SRuslan Bukin 	bus_space_tag_t		bst;
103484b4fd4SRuslan Bukin };
104484b4fd4SRuslan Bukin 
105484b4fd4SRuslan Bukin static phandle_t i2c_get_node(device_t, device_t);
106484b4fd4SRuslan Bukin static int i2c_probe(device_t);
107484b4fd4SRuslan Bukin static int i2c_attach(device_t);
108484b4fd4SRuslan Bukin 
109484b4fd4SRuslan Bukin static int i2c_repeated_start(device_t, u_char, int);
110484b4fd4SRuslan Bukin static int i2c_start(device_t, u_char, int);
111484b4fd4SRuslan Bukin static int i2c_stop(device_t);
112484b4fd4SRuslan Bukin static int i2c_reset(device_t, u_char, u_char, u_char *);
113484b4fd4SRuslan Bukin static int i2c_read(device_t, char *, int, int *, int, int);
114484b4fd4SRuslan Bukin static int i2c_write(device_t, const char *, int, int *, int);
115484b4fd4SRuslan Bukin 
116484b4fd4SRuslan Bukin static device_method_t i2c_methods[] = {
117484b4fd4SRuslan Bukin 	DEVMETHOD(device_probe,			i2c_probe),
118484b4fd4SRuslan Bukin 	DEVMETHOD(device_attach,		i2c_attach),
119484b4fd4SRuslan Bukin 
120484b4fd4SRuslan Bukin 	/* OFW methods */
121484b4fd4SRuslan Bukin 	DEVMETHOD(ofw_bus_get_node,		i2c_get_node),
122484b4fd4SRuslan Bukin 
123484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_callback,		iicbus_null_callback),
124484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_repeated_start,	i2c_repeated_start),
125484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_start,			i2c_start),
126484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_stop,			i2c_stop),
127484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_reset,			i2c_reset),
128484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_read,			i2c_read),
129484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_write,			i2c_write),
130484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_transfer,		iicbus_transfer_gen),
131484b4fd4SRuslan Bukin 
132484b4fd4SRuslan Bukin 	{ 0, 0 }
133484b4fd4SRuslan Bukin };
134484b4fd4SRuslan Bukin 
135484b4fd4SRuslan Bukin static driver_t i2c_driver = {
136484b4fd4SRuslan Bukin 	"iichb",
137484b4fd4SRuslan Bukin 	i2c_methods,
138484b4fd4SRuslan Bukin 	sizeof(struct i2c_softc),
139484b4fd4SRuslan Bukin };
140484b4fd4SRuslan Bukin static devclass_t  i2c_devclass;
141484b4fd4SRuslan Bukin 
142484b4fd4SRuslan Bukin DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0);
143484b4fd4SRuslan Bukin DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0);
144484b4fd4SRuslan Bukin 
145484b4fd4SRuslan Bukin static phandle_t
146484b4fd4SRuslan Bukin i2c_get_node(device_t bus, device_t dev)
147484b4fd4SRuslan Bukin {
148484b4fd4SRuslan Bukin 	/*
149484b4fd4SRuslan Bukin 	 * Share controller node with iicbus device
150484b4fd4SRuslan Bukin 	 */
151484b4fd4SRuslan Bukin 	return ofw_bus_get_node(bus);
152484b4fd4SRuslan Bukin }
153484b4fd4SRuslan Bukin 
154484b4fd4SRuslan Bukin static __inline void
155484b4fd4SRuslan Bukin i2c_write_reg(struct i2c_softc *sc, bus_size_t off, uint8_t val)
156484b4fd4SRuslan Bukin {
157484b4fd4SRuslan Bukin 
158484b4fd4SRuslan Bukin 	bus_space_write_1(sc->bst, sc->bsh, off, val);
159484b4fd4SRuslan Bukin }
160484b4fd4SRuslan Bukin 
161484b4fd4SRuslan Bukin static __inline uint8_t
162484b4fd4SRuslan Bukin i2c_read_reg(struct i2c_softc *sc, bus_size_t off)
163484b4fd4SRuslan Bukin {
164484b4fd4SRuslan Bukin 
165484b4fd4SRuslan Bukin 	return (bus_space_read_1(sc->bst, sc->bsh, off));
166484b4fd4SRuslan Bukin }
167484b4fd4SRuslan Bukin 
168484b4fd4SRuslan Bukin static __inline void
169484b4fd4SRuslan Bukin i2c_flag_set(struct i2c_softc *sc, bus_size_t off, uint8_t mask)
170484b4fd4SRuslan Bukin {
171484b4fd4SRuslan Bukin 	uint8_t status;
172484b4fd4SRuslan Bukin 
173484b4fd4SRuslan Bukin 	status = i2c_read_reg(sc, off);
174484b4fd4SRuslan Bukin 	status |= mask;
175484b4fd4SRuslan Bukin 	i2c_write_reg(sc, off, status);
176484b4fd4SRuslan Bukin }
177484b4fd4SRuslan Bukin 
178484b4fd4SRuslan Bukin /* Wait for transfer interrupt flag */
179484b4fd4SRuslan Bukin static int
180484b4fd4SRuslan Bukin wait_for_iif(struct i2c_softc *sc)
181484b4fd4SRuslan Bukin {
182484b4fd4SRuslan Bukin 	int retry;
183484b4fd4SRuslan Bukin 
184484b4fd4SRuslan Bukin 	retry = 1000;
185484b4fd4SRuslan Bukin 	while (retry --) {
186484b4fd4SRuslan Bukin 		if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MIF)
187484b4fd4SRuslan Bukin 			return (IIC_NOERR);
188484b4fd4SRuslan Bukin 		DELAY(10);
189484b4fd4SRuslan Bukin 	}
190484b4fd4SRuslan Bukin 
191484b4fd4SRuslan Bukin 	return (IIC_ETIMEOUT);
192484b4fd4SRuslan Bukin }
193484b4fd4SRuslan Bukin 
194484b4fd4SRuslan Bukin /* Wait for free bus */
195484b4fd4SRuslan Bukin static int
196484b4fd4SRuslan Bukin wait_for_nibb(struct i2c_softc *sc)
197484b4fd4SRuslan Bukin {
198484b4fd4SRuslan Bukin 	int retry;
199484b4fd4SRuslan Bukin 
200484b4fd4SRuslan Bukin 	retry = 1000;
201484b4fd4SRuslan Bukin 	while (retry --) {
202484b4fd4SRuslan Bukin 		if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0)
203484b4fd4SRuslan Bukin 			return (IIC_NOERR);
204484b4fd4SRuslan Bukin 		DELAY(10);
205484b4fd4SRuslan Bukin 	}
206484b4fd4SRuslan Bukin 
207484b4fd4SRuslan Bukin 	return (IIC_ETIMEOUT);
208484b4fd4SRuslan Bukin }
209484b4fd4SRuslan Bukin 
210484b4fd4SRuslan Bukin /* Wait for transfer complete+interrupt flag */
211484b4fd4SRuslan Bukin static int
212484b4fd4SRuslan Bukin wait_for_icf(struct i2c_softc *sc)
213484b4fd4SRuslan Bukin {
214484b4fd4SRuslan Bukin 	int retry;
215484b4fd4SRuslan Bukin 
216484b4fd4SRuslan Bukin 	retry = 1000;
217484b4fd4SRuslan Bukin 	while (retry --) {
218484b4fd4SRuslan Bukin 
219484b4fd4SRuslan Bukin 		if ((i2c_read_reg(sc, I2C_STATUS_REG) &
220484b4fd4SRuslan Bukin 		    (I2CSR_MCF|I2CSR_MIF)) == (I2CSR_MCF|I2CSR_MIF))
221484b4fd4SRuslan Bukin 			return (IIC_NOERR);
222484b4fd4SRuslan Bukin 		DELAY(10);
223484b4fd4SRuslan Bukin 	}
224484b4fd4SRuslan Bukin 
225484b4fd4SRuslan Bukin 	return (IIC_ETIMEOUT);
226484b4fd4SRuslan Bukin }
227484b4fd4SRuslan Bukin 
228484b4fd4SRuslan Bukin static int
229484b4fd4SRuslan Bukin i2c_probe(device_t dev)
230484b4fd4SRuslan Bukin {
231484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
232484b4fd4SRuslan Bukin 
233484b4fd4SRuslan Bukin 	if (!ofw_bus_status_okay(dev))
234484b4fd4SRuslan Bukin 		return (ENXIO);
235484b4fd4SRuslan Bukin 
236*40d7d632SRuslan Bukin 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
237484b4fd4SRuslan Bukin 		return (ENXIO);
238484b4fd4SRuslan Bukin 
239484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
240484b4fd4SRuslan Bukin 	sc->rid = 0;
241484b4fd4SRuslan Bukin 
242484b4fd4SRuslan Bukin 	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
243484b4fd4SRuslan Bukin 	    RF_ACTIVE);
244484b4fd4SRuslan Bukin 	if (sc->res == NULL) {
245484b4fd4SRuslan Bukin 		device_printf(dev, "could not allocate resources\n");
246484b4fd4SRuslan Bukin 		return (ENXIO);
247484b4fd4SRuslan Bukin 	}
248484b4fd4SRuslan Bukin 
249484b4fd4SRuslan Bukin 	sc->bst = rman_get_bustag(sc->res);
250484b4fd4SRuslan Bukin 	sc->bsh = rman_get_bushandle(sc->res);
251484b4fd4SRuslan Bukin 
252484b4fd4SRuslan Bukin 	/* Enable I2C */
253484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN);
254484b4fd4SRuslan Bukin 	bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
255*40d7d632SRuslan Bukin 	device_set_desc(dev, "Freescale i.MX I2C bus controller");
256484b4fd4SRuslan Bukin 
257484b4fd4SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
258484b4fd4SRuslan Bukin }
259484b4fd4SRuslan Bukin 
260484b4fd4SRuslan Bukin static int
261484b4fd4SRuslan Bukin i2c_attach(device_t dev)
262484b4fd4SRuslan Bukin {
263484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
264484b4fd4SRuslan Bukin 
265484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
266484b4fd4SRuslan Bukin 	sc->dev = dev;
267484b4fd4SRuslan Bukin 	sc->rid = 0;
268484b4fd4SRuslan Bukin 
269484b4fd4SRuslan Bukin 	mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF);
270484b4fd4SRuslan Bukin 
271484b4fd4SRuslan Bukin 	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
272484b4fd4SRuslan Bukin 	    RF_ACTIVE);
273484b4fd4SRuslan Bukin 	if (sc->res == NULL) {
274484b4fd4SRuslan Bukin 		device_printf(dev, "could not allocate resources");
275484b4fd4SRuslan Bukin 		mtx_destroy(&sc->mutex);
276484b4fd4SRuslan Bukin 		return (ENXIO);
277484b4fd4SRuslan Bukin 	}
278484b4fd4SRuslan Bukin 
279484b4fd4SRuslan Bukin 	sc->bst = rman_get_bustag(sc->res);
280484b4fd4SRuslan Bukin 	sc->bsh = rman_get_bushandle(sc->res);
281484b4fd4SRuslan Bukin 
282484b4fd4SRuslan Bukin 	sc->iicbus = device_add_child(dev, "iicbus", -1);
283484b4fd4SRuslan Bukin 	if (sc->iicbus == NULL) {
284484b4fd4SRuslan Bukin 		device_printf(dev, "could not add iicbus child");
285484b4fd4SRuslan Bukin 		mtx_destroy(&sc->mutex);
286484b4fd4SRuslan Bukin 		return (ENXIO);
287484b4fd4SRuslan Bukin 	}
288484b4fd4SRuslan Bukin 
289484b4fd4SRuslan Bukin 	bus_generic_attach(dev);
290484b4fd4SRuslan Bukin 	return (IIC_NOERR);
291484b4fd4SRuslan Bukin }
292484b4fd4SRuslan Bukin 
293484b4fd4SRuslan Bukin static int
294484b4fd4SRuslan Bukin i2c_repeated_start(device_t dev, u_char slave, int timeout)
295484b4fd4SRuslan Bukin {
296484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
297484b4fd4SRuslan Bukin 	int error;
298484b4fd4SRuslan Bukin 
299484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
300484b4fd4SRuslan Bukin 
301484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
302484b4fd4SRuslan Bukin 
303484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_ADDR_REG, slave);
304484b4fd4SRuslan Bukin 	if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0) {
305484b4fd4SRuslan Bukin 		mtx_unlock(&sc->mutex);
306484b4fd4SRuslan Bukin 		return (IIC_EBUSBSY);
307484b4fd4SRuslan Bukin 	}
308484b4fd4SRuslan Bukin 
309484b4fd4SRuslan Bukin 	/* Set repeated start condition */
310484b4fd4SRuslan Bukin 	DELAY(10);
311484b4fd4SRuslan Bukin 	i2c_flag_set(sc, I2C_CONTROL_REG, I2CCR_RSTA);
312484b4fd4SRuslan Bukin 	DELAY(10);
313484b4fd4SRuslan Bukin 	/* Clear status */
314484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
315484b4fd4SRuslan Bukin 	/* Write target address - LSB is R/W bit */
316484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_DATA_REG, slave);
317484b4fd4SRuslan Bukin 
318484b4fd4SRuslan Bukin 	error = wait_for_iif(sc);
319484b4fd4SRuslan Bukin 
320484b4fd4SRuslan Bukin 	/* Clear status */
321484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
322484b4fd4SRuslan Bukin 
323484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
324484b4fd4SRuslan Bukin 
325484b4fd4SRuslan Bukin 	if (error)
326484b4fd4SRuslan Bukin 		return (error);
327484b4fd4SRuslan Bukin 
328484b4fd4SRuslan Bukin 	return (IIC_NOERR);
329484b4fd4SRuslan Bukin }
330484b4fd4SRuslan Bukin 
331484b4fd4SRuslan Bukin static int
332484b4fd4SRuslan Bukin i2c_start(device_t dev, u_char slave, int timeout)
333484b4fd4SRuslan Bukin {
334484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
335484b4fd4SRuslan Bukin 	int error;
336484b4fd4SRuslan Bukin 
337484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
338484b4fd4SRuslan Bukin 
339484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
340484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_ADDR_REG, slave);
341484b4fd4SRuslan Bukin 	if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) {
342484b4fd4SRuslan Bukin 		mtx_unlock(&sc->mutex);
343484b4fd4SRuslan Bukin 		return (IIC_EBUSBSY);
344484b4fd4SRuslan Bukin 	}
345484b4fd4SRuslan Bukin 
346484b4fd4SRuslan Bukin 	/* Set start condition */
347484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG,
348484b4fd4SRuslan Bukin 	    I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK);
349484b4fd4SRuslan Bukin 	DELAY(100);
350484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG,
351484b4fd4SRuslan Bukin 	    I2CCR_MEN | I2CCR_MSTA | I2CCR_MTX | I2CCR_TXAK);
352484b4fd4SRuslan Bukin 	/* Clear status */
353484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
354484b4fd4SRuslan Bukin 	/* Write target address - LSB is R/W bit */
355484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_DATA_REG, slave);
356484b4fd4SRuslan Bukin 
357484b4fd4SRuslan Bukin 	error = wait_for_iif(sc);
358484b4fd4SRuslan Bukin 
359484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
360484b4fd4SRuslan Bukin 	if (error)
361484b4fd4SRuslan Bukin 		return (error);
362484b4fd4SRuslan Bukin 
363484b4fd4SRuslan Bukin 	return (IIC_NOERR);
364484b4fd4SRuslan Bukin }
365484b4fd4SRuslan Bukin 
366484b4fd4SRuslan Bukin 
367484b4fd4SRuslan Bukin static int
368484b4fd4SRuslan Bukin i2c_stop(device_t dev)
369484b4fd4SRuslan Bukin {
370484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
371484b4fd4SRuslan Bukin 
372484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
373484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
374484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK);
375484b4fd4SRuslan Bukin 	DELAY(100);
376484b4fd4SRuslan Bukin 	/* Reset controller if bus still busy after STOP */
377484b4fd4SRuslan Bukin 	if (wait_for_nibb(sc) == IIC_ETIMEOUT) {
378484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_CONTROL_REG, 0);
379484b4fd4SRuslan Bukin 		DELAY(1000);
380484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK);
381484b4fd4SRuslan Bukin 
382484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
383484b4fd4SRuslan Bukin 	}
384484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
385484b4fd4SRuslan Bukin 
386484b4fd4SRuslan Bukin 	return (IIC_NOERR);
387484b4fd4SRuslan Bukin }
388484b4fd4SRuslan Bukin 
389484b4fd4SRuslan Bukin static int
390484b4fd4SRuslan Bukin i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr)
391484b4fd4SRuslan Bukin {
392484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
393484b4fd4SRuslan Bukin 	uint8_t baud_rate;
394484b4fd4SRuslan Bukin 
395484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
396484b4fd4SRuslan Bukin 
397484b4fd4SRuslan Bukin 	switch (speed) {
398484b4fd4SRuslan Bukin 	case IIC_FAST:
399484b4fd4SRuslan Bukin 		baud_rate = I2C_BAUD_RATE_FAST;
400484b4fd4SRuslan Bukin 		break;
401484b4fd4SRuslan Bukin 	case IIC_SLOW:
402484b4fd4SRuslan Bukin 	case IIC_UNKNOWN:
403484b4fd4SRuslan Bukin 	case IIC_FASTEST:
404484b4fd4SRuslan Bukin 	default:
405484b4fd4SRuslan Bukin 		baud_rate = I2C_BAUD_RATE_DEF;
406484b4fd4SRuslan Bukin 		break;
407484b4fd4SRuslan Bukin 	}
408484b4fd4SRuslan Bukin 
409484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
410484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, 0x0);
411484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
412484b4fd4SRuslan Bukin 	DELAY(1000);
413484b4fd4SRuslan Bukin 
414484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_FDR_REG, 20);
415484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN);
416484b4fd4SRuslan Bukin 	DELAY(1000);
417484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
418484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
419484b4fd4SRuslan Bukin 
420484b4fd4SRuslan Bukin 	return (IIC_NOERR);
421484b4fd4SRuslan Bukin }
422484b4fd4SRuslan Bukin 
423484b4fd4SRuslan Bukin static int
424484b4fd4SRuslan Bukin i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay)
425484b4fd4SRuslan Bukin {
426484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
427484b4fd4SRuslan Bukin 	int error, reg;
428484b4fd4SRuslan Bukin 
429484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
430484b4fd4SRuslan Bukin 	*read = 0;
431484b4fd4SRuslan Bukin 
432484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
433484b4fd4SRuslan Bukin 
434484b4fd4SRuslan Bukin 	if (len) {
435484b4fd4SRuslan Bukin 		if (len == 1)
436484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
437484b4fd4SRuslan Bukin 			    I2CCR_MSTA | I2CCR_TXAK);
438484b4fd4SRuslan Bukin 
439484b4fd4SRuslan Bukin 		else
440484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
441484b4fd4SRuslan Bukin 			    I2CCR_MSTA);
442484b4fd4SRuslan Bukin 
443484b4fd4SRuslan Bukin 		/* dummy read */
444484b4fd4SRuslan Bukin 		i2c_read_reg(sc, I2C_DATA_REG);
445484b4fd4SRuslan Bukin 		DELAY(1000);
446484b4fd4SRuslan Bukin 	}
447484b4fd4SRuslan Bukin 
448484b4fd4SRuslan Bukin 	while (*read < len) {
449484b4fd4SRuslan Bukin 		error = wait_for_icf(sc);
450484b4fd4SRuslan Bukin 		if (error) {
451484b4fd4SRuslan Bukin 			mtx_unlock(&sc->mutex);
452484b4fd4SRuslan Bukin 			return (error);
453484b4fd4SRuslan Bukin 		}
454484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
455484b4fd4SRuslan Bukin 		if ((*read == len - 2) && last) {
456484b4fd4SRuslan Bukin 			/* NO ACK on last byte */
457484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
458484b4fd4SRuslan Bukin 			    I2CCR_MSTA | I2CCR_TXAK);
459484b4fd4SRuslan Bukin 		}
460484b4fd4SRuslan Bukin 
461484b4fd4SRuslan Bukin 		if ((*read == len - 1) && last) {
462484b4fd4SRuslan Bukin 			/* Transfer done, remove master bit */
463484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
464484b4fd4SRuslan Bukin 			    I2CCR_TXAK);
465484b4fd4SRuslan Bukin 		}
466484b4fd4SRuslan Bukin 
467484b4fd4SRuslan Bukin 		reg = i2c_read_reg(sc, I2C_DATA_REG);
468484b4fd4SRuslan Bukin 		*buf++ = reg;
469484b4fd4SRuslan Bukin 		(*read)++;
470484b4fd4SRuslan Bukin 	}
471484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
472484b4fd4SRuslan Bukin 
473484b4fd4SRuslan Bukin 	return (IIC_NOERR);
474484b4fd4SRuslan Bukin }
475484b4fd4SRuslan Bukin 
476484b4fd4SRuslan Bukin static int
477484b4fd4SRuslan Bukin i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout)
478484b4fd4SRuslan Bukin {
479484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
480484b4fd4SRuslan Bukin 	int error;
481484b4fd4SRuslan Bukin 
482484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
483484b4fd4SRuslan Bukin 	*sent = 0;
484484b4fd4SRuslan Bukin 
485484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
486484b4fd4SRuslan Bukin 	while (*sent < len) {
487484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
488484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_DATA_REG, *buf++);
489484b4fd4SRuslan Bukin 
490484b4fd4SRuslan Bukin 		error = wait_for_iif(sc);
491484b4fd4SRuslan Bukin 		if (error) {
492484b4fd4SRuslan Bukin 			mtx_unlock(&sc->mutex);
493484b4fd4SRuslan Bukin 			return (error);
494484b4fd4SRuslan Bukin 		}
495484b4fd4SRuslan Bukin 
496484b4fd4SRuslan Bukin 		(*sent)++;
497484b4fd4SRuslan Bukin 	}
498484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
499484b4fd4SRuslan Bukin 
500484b4fd4SRuslan Bukin 	return (IIC_NOERR);
501484b4fd4SRuslan Bukin }
502