xref: /freebsd/sys/arm/freescale/imx/imx_i2c.c (revision 844aff82a6599a8d96545dfb89663809e71719fc)
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>
38*844aff82SIan Lepore #include <sys/limits.h>
39484b4fd4SRuslan Bukin #include <sys/module.h>
40484b4fd4SRuslan Bukin #include <sys/resource.h>
41484b4fd4SRuslan Bukin 
42484b4fd4SRuslan Bukin #include <machine/bus.h>
43484b4fd4SRuslan Bukin #include <machine/resource.h>
44484b4fd4SRuslan Bukin #include <sys/rman.h>
45484b4fd4SRuslan Bukin 
46484b4fd4SRuslan Bukin #include <sys/lock.h>
47484b4fd4SRuslan Bukin #include <sys/mutex.h>
48484b4fd4SRuslan Bukin 
49*844aff82SIan Lepore #include <arm/freescale/imx/imx_ccmvar.h>
50*844aff82SIan Lepore 
51484b4fd4SRuslan Bukin #include <dev/iicbus/iiconf.h>
52484b4fd4SRuslan Bukin #include <dev/iicbus/iicbus.h>
53484b4fd4SRuslan Bukin #include "iicbus_if.h"
54484b4fd4SRuslan Bukin 
55484b4fd4SRuslan Bukin #include <dev/fdt/fdt_common.h>
56484b4fd4SRuslan Bukin #include <dev/ofw/openfirm.h>
57484b4fd4SRuslan Bukin #include <dev/ofw/ofw_bus.h>
58484b4fd4SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
59484b4fd4SRuslan Bukin 
60484b4fd4SRuslan Bukin #define I2C_ADDR_REG		0x00 /* I2C slave address register */
61484b4fd4SRuslan Bukin #define I2C_FDR_REG		0x04 /* I2C frequency divider register */
62484b4fd4SRuslan Bukin #define I2C_CONTROL_REG		0x08 /* I2C control register */
63484b4fd4SRuslan Bukin #define I2C_STATUS_REG		0x0C /* I2C status register */
64484b4fd4SRuslan Bukin #define I2C_DATA_REG		0x10 /* I2C data register */
65484b4fd4SRuslan Bukin #define I2C_DFSRR_REG		0x14 /* I2C Digital Filter Sampling rate */
66484b4fd4SRuslan Bukin 
67484b4fd4SRuslan Bukin #define I2CCR_MEN		(1 << 7) /* Module enable */
68484b4fd4SRuslan Bukin #define I2CCR_MSTA		(1 << 5) /* Master/slave mode */
69484b4fd4SRuslan Bukin #define I2CCR_MTX		(1 << 4) /* Transmit/receive mode */
70484b4fd4SRuslan Bukin #define I2CCR_TXAK		(1 << 3) /* Transfer acknowledge */
71484b4fd4SRuslan Bukin #define I2CCR_RSTA		(1 << 2) /* Repeated START */
72484b4fd4SRuslan Bukin 
73484b4fd4SRuslan Bukin #define I2CSR_MCF		(1 << 7) /* Data transfer */
74484b4fd4SRuslan Bukin #define I2CSR_MASS		(1 << 6) /* Addressed as a slave */
75484b4fd4SRuslan Bukin #define I2CSR_MBB		(1 << 5) /* Bus busy */
76484b4fd4SRuslan Bukin #define I2CSR_MAL		(1 << 4) /* Arbitration lost */
77484b4fd4SRuslan Bukin #define I2CSR_SRW		(1 << 2) /* Slave read/write */
78484b4fd4SRuslan Bukin #define I2CSR_MIF		(1 << 1) /* Module interrupt */
79484b4fd4SRuslan Bukin #define I2CSR_RXAK		(1 << 0) /* Received acknowledge */
80484b4fd4SRuslan Bukin 
81484b4fd4SRuslan Bukin #define I2C_BAUD_RATE_FAST	0x31
82484b4fd4SRuslan Bukin #define I2C_BAUD_RATE_DEF	0x3F
83484b4fd4SRuslan Bukin #define I2C_DFSSR_DIV		0x10
84484b4fd4SRuslan Bukin 
85*844aff82SIan Lepore /*
86*844aff82SIan Lepore  * A table of available divisors and the associated coded values to put in the
87*844aff82SIan Lepore  * FDR register to achieve that divisor.. There is no algorithmic relationship I
88*844aff82SIan Lepore  * can see between divisors and the codes that go into the register.  The table
89*844aff82SIan Lepore  * begins and ends with entries that handle insane configuration values.
90*844aff82SIan Lepore  */
91*844aff82SIan Lepore struct clkdiv {
92*844aff82SIan Lepore 	u_int divisor;
93*844aff82SIan Lepore 	u_int regcode;
94*844aff82SIan Lepore };
95*844aff82SIan Lepore static struct clkdiv clkdiv_table[] = {
96*844aff82SIan Lepore         {    0, 0x20 }, {   22, 0x20 }, {   24, 0x21 }, {   26, 0x22 },
97*844aff82SIan Lepore         {   28, 0x23 }, {   30, 0x00 }, {   32, 0x24 }, {   36, 0x25 },
98*844aff82SIan Lepore         {   40, 0x26 }, {   42, 0x03 }, {   44, 0x27 }, {   48, 0x28 },
99*844aff82SIan Lepore         {   52, 0x05 }, {   56, 0x29 }, {   60, 0x06 }, {   64, 0x2a },
100*844aff82SIan Lepore         {   72, 0x2b }, {   80, 0x2c }, {   88, 0x09 }, {   96, 0x2d },
101*844aff82SIan Lepore         {  104, 0x0a }, {  112, 0x2e }, {  128, 0x2f }, {  144, 0x0c },
102*844aff82SIan Lepore         {  160, 0x30 }, {  192, 0x31 }, {  224, 0x32 }, {  240, 0x0f },
103*844aff82SIan Lepore         {  256, 0x33 }, {  288, 0x10 }, {  320, 0x34 }, {  384, 0x35 },
104*844aff82SIan Lepore         {  448, 0x36 }, {  480, 0x13 }, {  512, 0x37 }, {  576, 0x14 },
105*844aff82SIan Lepore         {  640, 0x38 }, {  768, 0x39 }, {  896, 0x3a }, {  960, 0x17 },
106*844aff82SIan Lepore         { 1024, 0x3b }, { 1152, 0x18 }, { 1280, 0x3c }, { 1536, 0x3d },
107*844aff82SIan Lepore         { 1792, 0x3e }, { 1920, 0x1b }, { 2048, 0x3f }, { 2304, 0x1c },
108*844aff82SIan Lepore         { 2560, 0x1d }, { 3072, 0x1e }, { 3840, 0x1f }, {UINT_MAX, 0x1f}
109*844aff82SIan Lepore };
110*844aff82SIan Lepore 
111484b4fd4SRuslan Bukin #ifdef  DEBUG
112484b4fd4SRuslan Bukin #define debugf(fmt, args...) do { printf("%s(): ", __func__);		\
113484b4fd4SRuslan Bukin 		printf(fmt,##args); } while (0)
114484b4fd4SRuslan Bukin #else
115484b4fd4SRuslan Bukin #define debugf(fmt, args...)
116484b4fd4SRuslan Bukin #endif
117484b4fd4SRuslan Bukin 
11840d7d632SRuslan Bukin static struct ofw_compat_data compat_data[] = {
11940d7d632SRuslan Bukin 	{"fsl,imx6q-i2c",  1},
12040d7d632SRuslan Bukin 	{"fsl,imx-i2c",	   1},
12140d7d632SRuslan Bukin 	{NULL,             0}
12240d7d632SRuslan Bukin };
12340d7d632SRuslan Bukin 
124484b4fd4SRuslan Bukin struct i2c_softc {
125484b4fd4SRuslan Bukin 	device_t		dev;
126484b4fd4SRuslan Bukin 	device_t		iicbus;
127484b4fd4SRuslan Bukin 	struct resource		*res;
128484b4fd4SRuslan Bukin 	struct mtx		mutex;
129484b4fd4SRuslan Bukin 	int			rid;
130484b4fd4SRuslan Bukin 	bus_space_handle_t	bsh;
131484b4fd4SRuslan Bukin 	bus_space_tag_t		bst;
132484b4fd4SRuslan Bukin };
133484b4fd4SRuslan Bukin 
134484b4fd4SRuslan Bukin static phandle_t i2c_get_node(device_t, device_t);
135484b4fd4SRuslan Bukin static int i2c_probe(device_t);
136484b4fd4SRuslan Bukin static int i2c_attach(device_t);
137484b4fd4SRuslan Bukin 
138484b4fd4SRuslan Bukin static int i2c_repeated_start(device_t, u_char, int);
139484b4fd4SRuslan Bukin static int i2c_start(device_t, u_char, int);
140484b4fd4SRuslan Bukin static int i2c_stop(device_t);
141484b4fd4SRuslan Bukin static int i2c_reset(device_t, u_char, u_char, u_char *);
142484b4fd4SRuslan Bukin static int i2c_read(device_t, char *, int, int *, int, int);
143484b4fd4SRuslan Bukin static int i2c_write(device_t, const char *, int, int *, int);
144484b4fd4SRuslan Bukin 
145484b4fd4SRuslan Bukin static device_method_t i2c_methods[] = {
146484b4fd4SRuslan Bukin 	DEVMETHOD(device_probe,			i2c_probe),
147484b4fd4SRuslan Bukin 	DEVMETHOD(device_attach,		i2c_attach),
148484b4fd4SRuslan Bukin 
149484b4fd4SRuslan Bukin 	/* OFW methods */
150484b4fd4SRuslan Bukin 	DEVMETHOD(ofw_bus_get_node,		i2c_get_node),
151484b4fd4SRuslan Bukin 
152484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_callback,		iicbus_null_callback),
153484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_repeated_start,	i2c_repeated_start),
154484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_start,			i2c_start),
155484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_stop,			i2c_stop),
156484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_reset,			i2c_reset),
157484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_read,			i2c_read),
158484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_write,			i2c_write),
159484b4fd4SRuslan Bukin 	DEVMETHOD(iicbus_transfer,		iicbus_transfer_gen),
160484b4fd4SRuslan Bukin 
161484b4fd4SRuslan Bukin 	{ 0, 0 }
162484b4fd4SRuslan Bukin };
163484b4fd4SRuslan Bukin 
164484b4fd4SRuslan Bukin static driver_t i2c_driver = {
165484b4fd4SRuslan Bukin 	"iichb",
166484b4fd4SRuslan Bukin 	i2c_methods,
167484b4fd4SRuslan Bukin 	sizeof(struct i2c_softc),
168484b4fd4SRuslan Bukin };
169484b4fd4SRuslan Bukin static devclass_t  i2c_devclass;
170484b4fd4SRuslan Bukin 
171484b4fd4SRuslan Bukin DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0);
172484b4fd4SRuslan Bukin DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0);
173484b4fd4SRuslan Bukin 
174484b4fd4SRuslan Bukin static phandle_t
175484b4fd4SRuslan Bukin i2c_get_node(device_t bus, device_t dev)
176484b4fd4SRuslan Bukin {
177484b4fd4SRuslan Bukin 	/*
178484b4fd4SRuslan Bukin 	 * Share controller node with iicbus device
179484b4fd4SRuslan Bukin 	 */
180484b4fd4SRuslan Bukin 	return ofw_bus_get_node(bus);
181484b4fd4SRuslan Bukin }
182484b4fd4SRuslan Bukin 
183484b4fd4SRuslan Bukin static __inline void
184484b4fd4SRuslan Bukin i2c_write_reg(struct i2c_softc *sc, bus_size_t off, uint8_t val)
185484b4fd4SRuslan Bukin {
186484b4fd4SRuslan Bukin 
187484b4fd4SRuslan Bukin 	bus_space_write_1(sc->bst, sc->bsh, off, val);
188484b4fd4SRuslan Bukin }
189484b4fd4SRuslan Bukin 
190484b4fd4SRuslan Bukin static __inline uint8_t
191484b4fd4SRuslan Bukin i2c_read_reg(struct i2c_softc *sc, bus_size_t off)
192484b4fd4SRuslan Bukin {
193484b4fd4SRuslan Bukin 
194484b4fd4SRuslan Bukin 	return (bus_space_read_1(sc->bst, sc->bsh, off));
195484b4fd4SRuslan Bukin }
196484b4fd4SRuslan Bukin 
197484b4fd4SRuslan Bukin static __inline void
198484b4fd4SRuslan Bukin i2c_flag_set(struct i2c_softc *sc, bus_size_t off, uint8_t mask)
199484b4fd4SRuslan Bukin {
200484b4fd4SRuslan Bukin 	uint8_t status;
201484b4fd4SRuslan Bukin 
202484b4fd4SRuslan Bukin 	status = i2c_read_reg(sc, off);
203484b4fd4SRuslan Bukin 	status |= mask;
204484b4fd4SRuslan Bukin 	i2c_write_reg(sc, off, status);
205484b4fd4SRuslan Bukin }
206484b4fd4SRuslan Bukin 
207484b4fd4SRuslan Bukin /* Wait for transfer interrupt flag */
208484b4fd4SRuslan Bukin static int
209484b4fd4SRuslan Bukin wait_for_iif(struct i2c_softc *sc)
210484b4fd4SRuslan Bukin {
211484b4fd4SRuslan Bukin 	int retry;
212484b4fd4SRuslan Bukin 
213484b4fd4SRuslan Bukin 	retry = 1000;
214484b4fd4SRuslan Bukin 	while (retry --) {
215484b4fd4SRuslan Bukin 		if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MIF)
216484b4fd4SRuslan Bukin 			return (IIC_NOERR);
217484b4fd4SRuslan Bukin 		DELAY(10);
218484b4fd4SRuslan Bukin 	}
219484b4fd4SRuslan Bukin 
220484b4fd4SRuslan Bukin 	return (IIC_ETIMEOUT);
221484b4fd4SRuslan Bukin }
222484b4fd4SRuslan Bukin 
223484b4fd4SRuslan Bukin /* Wait for free bus */
224484b4fd4SRuslan Bukin static int
225484b4fd4SRuslan Bukin wait_for_nibb(struct i2c_softc *sc)
226484b4fd4SRuslan Bukin {
227484b4fd4SRuslan Bukin 	int retry;
228484b4fd4SRuslan Bukin 
229484b4fd4SRuslan Bukin 	retry = 1000;
230484b4fd4SRuslan Bukin 	while (retry --) {
231484b4fd4SRuslan Bukin 		if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0)
232484b4fd4SRuslan Bukin 			return (IIC_NOERR);
233484b4fd4SRuslan Bukin 		DELAY(10);
234484b4fd4SRuslan Bukin 	}
235484b4fd4SRuslan Bukin 
236484b4fd4SRuslan Bukin 	return (IIC_ETIMEOUT);
237484b4fd4SRuslan Bukin }
238484b4fd4SRuslan Bukin 
239484b4fd4SRuslan Bukin /* Wait for transfer complete+interrupt flag */
240484b4fd4SRuslan Bukin static int
241484b4fd4SRuslan Bukin wait_for_icf(struct i2c_softc *sc)
242484b4fd4SRuslan Bukin {
243484b4fd4SRuslan Bukin 	int retry;
244484b4fd4SRuslan Bukin 
245484b4fd4SRuslan Bukin 	retry = 1000;
246484b4fd4SRuslan Bukin 	while (retry --) {
247484b4fd4SRuslan Bukin 
248484b4fd4SRuslan Bukin 		if ((i2c_read_reg(sc, I2C_STATUS_REG) &
249484b4fd4SRuslan Bukin 		    (I2CSR_MCF|I2CSR_MIF)) == (I2CSR_MCF|I2CSR_MIF))
250484b4fd4SRuslan Bukin 			return (IIC_NOERR);
251484b4fd4SRuslan Bukin 		DELAY(10);
252484b4fd4SRuslan Bukin 	}
253484b4fd4SRuslan Bukin 
254484b4fd4SRuslan Bukin 	return (IIC_ETIMEOUT);
255484b4fd4SRuslan Bukin }
256484b4fd4SRuslan Bukin 
257484b4fd4SRuslan Bukin static int
258484b4fd4SRuslan Bukin i2c_probe(device_t dev)
259484b4fd4SRuslan Bukin {
260484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
261484b4fd4SRuslan Bukin 
262484b4fd4SRuslan Bukin 	if (!ofw_bus_status_okay(dev))
263484b4fd4SRuslan Bukin 		return (ENXIO);
264484b4fd4SRuslan Bukin 
26540d7d632SRuslan Bukin 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
266484b4fd4SRuslan Bukin 		return (ENXIO);
267484b4fd4SRuslan Bukin 
268484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
269484b4fd4SRuslan Bukin 	sc->rid = 0;
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\n");
275484b4fd4SRuslan Bukin 		return (ENXIO);
276484b4fd4SRuslan Bukin 	}
277484b4fd4SRuslan Bukin 
278484b4fd4SRuslan Bukin 	sc->bst = rman_get_bustag(sc->res);
279484b4fd4SRuslan Bukin 	sc->bsh = rman_get_bushandle(sc->res);
280484b4fd4SRuslan Bukin 
281484b4fd4SRuslan Bukin 	/* Enable I2C */
282484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN);
283484b4fd4SRuslan Bukin 	bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
28440d7d632SRuslan Bukin 	device_set_desc(dev, "Freescale i.MX I2C bus controller");
285484b4fd4SRuslan Bukin 
286484b4fd4SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
287484b4fd4SRuslan Bukin }
288484b4fd4SRuslan Bukin 
289484b4fd4SRuslan Bukin static int
290484b4fd4SRuslan Bukin i2c_attach(device_t dev)
291484b4fd4SRuslan Bukin {
292484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
293484b4fd4SRuslan Bukin 
294484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
295484b4fd4SRuslan Bukin 	sc->dev = dev;
296484b4fd4SRuslan Bukin 	sc->rid = 0;
297484b4fd4SRuslan Bukin 
298484b4fd4SRuslan Bukin 	mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF);
299484b4fd4SRuslan Bukin 
300484b4fd4SRuslan Bukin 	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
301484b4fd4SRuslan Bukin 	    RF_ACTIVE);
302484b4fd4SRuslan Bukin 	if (sc->res == NULL) {
303484b4fd4SRuslan Bukin 		device_printf(dev, "could not allocate resources");
304484b4fd4SRuslan Bukin 		mtx_destroy(&sc->mutex);
305484b4fd4SRuslan Bukin 		return (ENXIO);
306484b4fd4SRuslan Bukin 	}
307484b4fd4SRuslan Bukin 
308484b4fd4SRuslan Bukin 	sc->bst = rman_get_bustag(sc->res);
309484b4fd4SRuslan Bukin 	sc->bsh = rman_get_bushandle(sc->res);
310484b4fd4SRuslan Bukin 
311484b4fd4SRuslan Bukin 	sc->iicbus = device_add_child(dev, "iicbus", -1);
312484b4fd4SRuslan Bukin 	if (sc->iicbus == NULL) {
313484b4fd4SRuslan Bukin 		device_printf(dev, "could not add iicbus child");
314484b4fd4SRuslan Bukin 		mtx_destroy(&sc->mutex);
315484b4fd4SRuslan Bukin 		return (ENXIO);
316484b4fd4SRuslan Bukin 	}
317484b4fd4SRuslan Bukin 
318484b4fd4SRuslan Bukin 	bus_generic_attach(dev);
319484b4fd4SRuslan Bukin 	return (IIC_NOERR);
320484b4fd4SRuslan Bukin }
321484b4fd4SRuslan Bukin 
322484b4fd4SRuslan Bukin static int
323484b4fd4SRuslan Bukin i2c_repeated_start(device_t dev, u_char slave, int timeout)
324484b4fd4SRuslan Bukin {
325484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
326484b4fd4SRuslan Bukin 	int error;
327484b4fd4SRuslan Bukin 
328484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
329484b4fd4SRuslan Bukin 
330484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
331484b4fd4SRuslan Bukin 
332484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_ADDR_REG, slave);
333484b4fd4SRuslan Bukin 	if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0) {
334484b4fd4SRuslan Bukin 		mtx_unlock(&sc->mutex);
335484b4fd4SRuslan Bukin 		return (IIC_EBUSBSY);
336484b4fd4SRuslan Bukin 	}
337484b4fd4SRuslan Bukin 
338484b4fd4SRuslan Bukin 	/* Set repeated start condition */
339484b4fd4SRuslan Bukin 	DELAY(10);
340484b4fd4SRuslan Bukin 	i2c_flag_set(sc, I2C_CONTROL_REG, I2CCR_RSTA);
341484b4fd4SRuslan Bukin 	DELAY(10);
342484b4fd4SRuslan Bukin 	/* Clear status */
343484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
344484b4fd4SRuslan Bukin 	/* Write target address - LSB is R/W bit */
345484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_DATA_REG, slave);
346484b4fd4SRuslan Bukin 
347484b4fd4SRuslan Bukin 	error = wait_for_iif(sc);
348484b4fd4SRuslan Bukin 
349484b4fd4SRuslan Bukin 	/* Clear status */
350484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
351484b4fd4SRuslan Bukin 
352484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
353484b4fd4SRuslan Bukin 
354484b4fd4SRuslan Bukin 	if (error)
355484b4fd4SRuslan Bukin 		return (error);
356484b4fd4SRuslan Bukin 
357484b4fd4SRuslan Bukin 	return (IIC_NOERR);
358484b4fd4SRuslan Bukin }
359484b4fd4SRuslan Bukin 
360484b4fd4SRuslan Bukin static int
361484b4fd4SRuslan Bukin i2c_start(device_t dev, u_char slave, int timeout)
362484b4fd4SRuslan Bukin {
363484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
364484b4fd4SRuslan Bukin 	int error;
365484b4fd4SRuslan Bukin 
366484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
367484b4fd4SRuslan Bukin 
368484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
369484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_ADDR_REG, slave);
370484b4fd4SRuslan Bukin 	if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) {
371484b4fd4SRuslan Bukin 		mtx_unlock(&sc->mutex);
372484b4fd4SRuslan Bukin 		return (IIC_EBUSBSY);
373484b4fd4SRuslan Bukin 	}
374484b4fd4SRuslan Bukin 
375484b4fd4SRuslan Bukin 	/* Set start condition */
376484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG,
377484b4fd4SRuslan Bukin 	    I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK);
378484b4fd4SRuslan Bukin 	DELAY(100);
379484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG,
380484b4fd4SRuslan Bukin 	    I2CCR_MEN | I2CCR_MSTA | I2CCR_MTX | I2CCR_TXAK);
381484b4fd4SRuslan Bukin 	/* Clear status */
382484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
383484b4fd4SRuslan Bukin 	/* Write target address - LSB is R/W bit */
384484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_DATA_REG, slave);
385484b4fd4SRuslan Bukin 
386484b4fd4SRuslan Bukin 	error = wait_for_iif(sc);
387484b4fd4SRuslan Bukin 
388484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
389484b4fd4SRuslan Bukin 	if (error)
390484b4fd4SRuslan Bukin 		return (error);
391484b4fd4SRuslan Bukin 
392484b4fd4SRuslan Bukin 	return (IIC_NOERR);
393484b4fd4SRuslan Bukin }
394484b4fd4SRuslan Bukin 
395484b4fd4SRuslan Bukin 
396484b4fd4SRuslan Bukin static int
397484b4fd4SRuslan Bukin i2c_stop(device_t dev)
398484b4fd4SRuslan Bukin {
399484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
400484b4fd4SRuslan Bukin 
401484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
402484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
403484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK);
404484b4fd4SRuslan Bukin 	DELAY(100);
405484b4fd4SRuslan Bukin 	/* Reset controller if bus still busy after STOP */
406484b4fd4SRuslan Bukin 	if (wait_for_nibb(sc) == IIC_ETIMEOUT) {
407484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_CONTROL_REG, 0);
408484b4fd4SRuslan Bukin 		DELAY(1000);
409484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK);
410484b4fd4SRuslan Bukin 
411484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
412484b4fd4SRuslan Bukin 	}
413484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
414484b4fd4SRuslan Bukin 
415484b4fd4SRuslan Bukin 	return (IIC_NOERR);
416484b4fd4SRuslan Bukin }
417484b4fd4SRuslan Bukin 
418484b4fd4SRuslan Bukin static int
419484b4fd4SRuslan Bukin i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr)
420484b4fd4SRuslan Bukin {
421484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
422*844aff82SIan Lepore 	u_int busfreq, div, i, ipgfreq;
423484b4fd4SRuslan Bukin 
424484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
425484b4fd4SRuslan Bukin 
426*844aff82SIan Lepore 	/*
427*844aff82SIan Lepore 	 * Look up the divisor that gives the nearest speed that doesn't exceed
428*844aff82SIan Lepore 	 * the configured value for the bus.
429*844aff82SIan Lepore 	 */
430*844aff82SIan Lepore 	ipgfreq = imx_ccm_ipg_hz();
431*844aff82SIan Lepore 	busfreq = IICBUS_GET_FREQUENCY(sc->iicbus, speed);
432*844aff82SIan Lepore 	div = (ipgfreq + busfreq - 1) / busfreq;
433*844aff82SIan Lepore 	for (i = 0; i < nitems(clkdiv_table); i++) {
434*844aff82SIan Lepore 		if (clkdiv_table[i].divisor >= div)
435484b4fd4SRuslan Bukin 			break;
436484b4fd4SRuslan Bukin 	}
437*844aff82SIan Lepore 	div = clkdiv_table[i].regcode;
438484b4fd4SRuslan Bukin 
439484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
440484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, 0x0);
441484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
442484b4fd4SRuslan Bukin 	DELAY(1000);
443484b4fd4SRuslan Bukin 
444*844aff82SIan Lepore 	i2c_write_reg(sc, I2C_FDR_REG, (uint8_t)div);
445484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN);
446484b4fd4SRuslan Bukin 	DELAY(1000);
447484b4fd4SRuslan Bukin 	i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
448484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
449484b4fd4SRuslan Bukin 
450484b4fd4SRuslan Bukin 	return (IIC_NOERR);
451484b4fd4SRuslan Bukin }
452484b4fd4SRuslan Bukin 
453484b4fd4SRuslan Bukin static int
454484b4fd4SRuslan Bukin i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay)
455484b4fd4SRuslan Bukin {
456484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
457484b4fd4SRuslan Bukin 	int error, reg;
458484b4fd4SRuslan Bukin 
459484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
460484b4fd4SRuslan Bukin 	*read = 0;
461484b4fd4SRuslan Bukin 
462484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
463484b4fd4SRuslan Bukin 
464484b4fd4SRuslan Bukin 	if (len) {
465484b4fd4SRuslan Bukin 		if (len == 1)
466484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
467484b4fd4SRuslan Bukin 			    I2CCR_MSTA | I2CCR_TXAK);
468484b4fd4SRuslan Bukin 
469484b4fd4SRuslan Bukin 		else
470484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
471484b4fd4SRuslan Bukin 			    I2CCR_MSTA);
472484b4fd4SRuslan Bukin 
473484b4fd4SRuslan Bukin 		/* dummy read */
474484b4fd4SRuslan Bukin 		i2c_read_reg(sc, I2C_DATA_REG);
475484b4fd4SRuslan Bukin 		DELAY(1000);
476484b4fd4SRuslan Bukin 	}
477484b4fd4SRuslan Bukin 
478484b4fd4SRuslan Bukin 	while (*read < len) {
479484b4fd4SRuslan Bukin 		error = wait_for_icf(sc);
480484b4fd4SRuslan Bukin 		if (error) {
481484b4fd4SRuslan Bukin 			mtx_unlock(&sc->mutex);
482484b4fd4SRuslan Bukin 			return (error);
483484b4fd4SRuslan Bukin 		}
484484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
485484b4fd4SRuslan Bukin 		if ((*read == len - 2) && last) {
486484b4fd4SRuslan Bukin 			/* NO ACK on last byte */
487484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
488484b4fd4SRuslan Bukin 			    I2CCR_MSTA | I2CCR_TXAK);
489484b4fd4SRuslan Bukin 		}
490484b4fd4SRuslan Bukin 
491484b4fd4SRuslan Bukin 		if ((*read == len - 1) && last) {
492484b4fd4SRuslan Bukin 			/* Transfer done, remove master bit */
493484b4fd4SRuslan Bukin 			i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN |
494484b4fd4SRuslan Bukin 			    I2CCR_TXAK);
495484b4fd4SRuslan Bukin 		}
496484b4fd4SRuslan Bukin 
497484b4fd4SRuslan Bukin 		reg = i2c_read_reg(sc, I2C_DATA_REG);
498484b4fd4SRuslan Bukin 		*buf++ = reg;
499484b4fd4SRuslan Bukin 		(*read)++;
500484b4fd4SRuslan Bukin 	}
501484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
502484b4fd4SRuslan Bukin 
503484b4fd4SRuslan Bukin 	return (IIC_NOERR);
504484b4fd4SRuslan Bukin }
505484b4fd4SRuslan Bukin 
506484b4fd4SRuslan Bukin static int
507484b4fd4SRuslan Bukin i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout)
508484b4fd4SRuslan Bukin {
509484b4fd4SRuslan Bukin 	struct i2c_softc *sc;
510484b4fd4SRuslan Bukin 	int error;
511484b4fd4SRuslan Bukin 
512484b4fd4SRuslan Bukin 	sc = device_get_softc(dev);
513484b4fd4SRuslan Bukin 	*sent = 0;
514484b4fd4SRuslan Bukin 
515484b4fd4SRuslan Bukin 	mtx_lock(&sc->mutex);
516484b4fd4SRuslan Bukin 	while (*sent < len) {
517484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_STATUS_REG, 0x0);
518484b4fd4SRuslan Bukin 		i2c_write_reg(sc, I2C_DATA_REG, *buf++);
519484b4fd4SRuslan Bukin 
520484b4fd4SRuslan Bukin 		error = wait_for_iif(sc);
521484b4fd4SRuslan Bukin 		if (error) {
522484b4fd4SRuslan Bukin 			mtx_unlock(&sc->mutex);
523484b4fd4SRuslan Bukin 			return (error);
524484b4fd4SRuslan Bukin 		}
525484b4fd4SRuslan Bukin 
526484b4fd4SRuslan Bukin 		(*sent)++;
527484b4fd4SRuslan Bukin 	}
528484b4fd4SRuslan Bukin 	mtx_unlock(&sc->mutex);
529484b4fd4SRuslan Bukin 
530484b4fd4SRuslan Bukin 	return (IIC_NOERR);
531484b4fd4SRuslan Bukin }
532