xlr_i2c.c revision 241844
1198160Srrs/*-
2198160Srrs * Copyright (c) 2003-2009 RMI Corporation
3198160Srrs * All rights reserved.
4198160Srrs *
5198160Srrs * Redistribution and use in source and binary forms, with or without
6198160Srrs * modification, are permitted provided that the following conditions
7198160Srrs * are met:
8198160Srrs * 1. Redistributions of source code must retain the above copyright
9198160Srrs *    notice, this list of conditions and the following disclaimer.
10198160Srrs * 2. Redistributions in binary form must reproduce the above copyright
11198160Srrs *    notice, this list of conditions and the following disclaimer in the
12198160Srrs *    documentation and/or other materials provided with the distribution.
13198160Srrs * 3. Neither the name of RMI Corporation, nor the names of its contributors,
14198160Srrs *    may be used to endorse or promote products derived from this software
15198160Srrs *    without specific prior written permission.
16198160Srrs *
17198160Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18198160Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19198160Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20198160Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21198160Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22198160Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23198160Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24198160Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25198160Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26198160Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27198160Srrs * SUCH DAMAGE.
28198160Srrs *
29198160Srrs * RMI_BSD */
30198160Srrs
31198160Srrs#include <sys/cdefs.h>
32202173Simp__FBSDID("$FreeBSD: head/sys/mips/rmi/xlr_i2c.c 241844 2012-10-22 03:00:37Z eadler $");
33198160Srrs
34198160Srrs/*
35198160Srrs * I2C driver for the Palm-BK3220 I2C Host adapter on the RMI XLR.
36198160Srrs */
37198160Srrs
38198160Srrs#include <sys/param.h>
39198160Srrs#include <sys/systm.h>
40198160Srrs#include <sys/kernel.h>
41216390Sjchandra#include <sys/lock.h>
42198160Srrs#include <sys/module.h>
43216390Sjchandra#include <sys/mutex.h>
44198625Srrs#include <sys/bus.h>
45198160Srrs#include <sys/rman.h>
46198160Srrs
47198160Srrs
48198160Srrs#include <dev/iicbus/iiconf.h>
49198160Srrs#include <dev/iicbus/iicbus.h>
50198160Srrs
51216390Sjchandra#include <mips/rmi/board.h>
52198607Srrs#include <mips/rmi/iomap.h>
53198160Srrs#include <mips/include/resource.h>
54198160Srrs
55198160Srrs#include "iicbus_if.h"
56198160Srrs
57216390Sjchandra/* XLR I2C REGISTERS */
58216390Sjchandra#define XLR_I2C_CFG            0x00
59216390Sjchandra#define XLR_I2C_CLKDIV         0x01
60216390Sjchandra#define XLR_I2C_DEVADDR        0x02
61216390Sjchandra#define XLR_I2C_ADDR           0x03
62216390Sjchandra#define XLR_I2C_DATAOUT        0x04
63216390Sjchandra#define XLR_I2C_DATAIN         0x05
64216390Sjchandra#define XLR_I2C_STATUS         0x06
65216390Sjchandra#define XLR_I2C_STARTXFR       0x07
66216390Sjchandra#define XLR_I2C_BYTECNT        0x08
67216390Sjchandra#define XLR_I2C_HDSTATIM       0x09
68198160Srrs
69216390Sjchandra/* XLR I2C REGISTERS FLAGS */
70216390Sjchandra#define XLR_I2C_BUS_BUSY	0x01
71216390Sjchandra#define XLR_I2C_SDOEMPTY	0x02
72216390Sjchandra#define XLR_I2C_RXRDY       	0x04
73216390Sjchandra#define XLR_I2C_ACK_ERR		0x08
74216390Sjchandra#define XLR_I2C_ARB_STARTERR	0x30
75198160Srrs
76216390Sjchandra/* Register Programming Values!! Change as required */
77216390Sjchandra#define XLR_I2C_CFG_ADDR	0xF8	/* 8-Bit dev Addr + POR Values */
78216390Sjchandra#define XLR_I2C_CFG_NOADDR	0xFA	/* 8-Bit reg Addr + POR Values  : No dev addr */
79216390Sjchandra#define XLR_I2C_STARTXFR_ND	0x02	/* No data , only addr */
80216390Sjchandra#define XLR_I2C_STARTXFR_RD	0x01	/* Read */
81216390Sjchandra#define XLR_I2C_STARTXFR_WR	0x00	/* Write */
82216390Sjchandra#define XLR_I2C_CLKDIV_DEF	0x14A	/* 0x00000052 */
83216390Sjchandra#define XLR_I2C_HDSTATIM_DEF	0x107	/* 0x00000000 */
84198160Srrs
85216390Sjchandra#define MAXTIME 0x10000
86216390Sjchandra#define ARIZONA_I2C_BUS 1
87198160Srrs
88198160Srrsstatic devclass_t xlr_i2c_devclass;
89198160Srrs
90198160Srrs/*
91198160Srrs * Device methods
92198160Srrs */
93198160Srrsstatic int xlr_i2c_probe(device_t);
94198160Srrsstatic int xlr_i2c_attach(device_t);
95198160Srrsstatic int xlr_i2c_detach(device_t);
96198160Srrs
97198160Srrsstatic int xlr_i2c_start(device_t dev, u_char slave, int timeout);
98198160Srrsstatic int xlr_i2c_stop(device_t dev);
99198625Srrsstatic int xlr_i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay);
100216390Sjchandrastatic int xlr_i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout);
101216390Sjchandrastatic int xlr_i2c_callback(device_t dev, int index, caddr_t data);
102216390Sjchandrastatic int xlr_i2c_repeated_start(device_t dev, u_char slave, int timeout);
103216390Sjchandrastatic int xlr_i2c_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs);
104198160Srrs
105198625Srrsstruct xlr_i2c_softc {
106216390Sjchandra	device_t dev;		/* Self */
107198625Srrs	struct resource *mem_res;	/* Memory resource */
108198625Srrs	volatile int flags;
109198625Srrs	int sc_started;
110216390Sjchandra	uint8_t i2cdev_addr;
111216390Sjchandra	xlr_reg_t *iobase_i2c_regs;
112198625Srrs	device_t iicbus;
113216390Sjchandra	struct mtx sc_mtx;
114198160Srrs};
115198160Srrs
116216390Sjchandrastatic void
117216390Sjchandraset_i2c_base(device_t dev)
118216390Sjchandra{
119216390Sjchandra	struct xlr_i2c_softc *sc;
120198160Srrs
121216390Sjchandra	sc = device_get_softc(dev);
122216390Sjchandra	if (device_get_unit(dev) == 0)
123216390Sjchandra		sc->iobase_i2c_regs = xlr_io_mmio(XLR_IO_I2C_0_OFFSET);
124198625Srrs	else
125216390Sjchandra		sc->iobase_i2c_regs = xlr_io_mmio(XLR_IO_I2C_1_OFFSET);
126198160Srrs}
127198160Srrs
128198625Srrsstatic void
129216390Sjchandraxlr_i2c_dev_write(device_t dev, int reg, int value)
130198160Srrs{
131216390Sjchandra	struct xlr_i2c_softc *sc;
132216390Sjchandra
133216390Sjchandra	sc = device_get_softc(dev);
134216390Sjchandra	xlr_write_reg(sc->iobase_i2c_regs, reg, value);
135198625Srrs	return;
136198160Srrs}
137198160Srrs
138198160Srrs
139198625Srrsstatic int
140216390Sjchandraxlr_i2c_dev_read(device_t dev, int reg)
141198160Srrs{
142198625Srrs	uint32_t val;
143216390Sjchandra	struct xlr_i2c_softc *sc;
144198625Srrs
145216390Sjchandra	sc = device_get_softc(dev);
146216390Sjchandra	val = xlr_read_reg(sc->iobase_i2c_regs, reg);
147198625Srrs	return ((int)val);
148198160Srrs}
149198160Srrs
150198160Srrs
151198160Srrsstatic int
152198160Srrsxlr_i2c_probe(device_t dev)
153198160Srrs{
154216390Sjchandra	device_set_desc(dev, "XLR/XLS I2C bus controller");
155198160Srrs
156198160Srrs	return (0);
157198160Srrs}
158198160Srrs
159198160Srrs
160198160Srrs/*
161198160Srrs * We add all the devices which we know about.
162198160Srrs * The generic attach routine will attach them if they are alive.
163198160Srrs */
164198160Srrsstatic int
165198160Srrsxlr_i2c_attach(device_t dev)
166198160Srrs{
167216390Sjchandra	int rid;
168198625Srrs	struct xlr_i2c_softc *sc;
169216390Sjchandra	device_t tmpd;
170198160Srrs
171216390Sjchandra	if(device_get_unit(dev)!=ARIZONA_I2C_BUS) {
172216390Sjchandra		device_printf(dev, "unused iicbus instance\n");
173216390Sjchandra		return 0;
174216390Sjchandra	}
175216390Sjchandra
176198625Srrs	sc = device_get_softc(dev);
177216390Sjchandra	set_i2c_base(dev);
178216390Sjchandra
179216390Sjchandra	mtx_init(&sc->sc_mtx, "xlr_i2c", "xlr_i2c", MTX_DEF);
180216390Sjchandra
181216390Sjchandra	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
182198625Srrs	if (sc->mem_res == NULL) {
183198625Srrs		printf("not able to allocate the bus resource\n");
184198625Srrs	}
185216390Sjchandra	if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) {
186198625Srrs		printf("could not allocate iicbus instance\n");
187216390Sjchandra		return -1;
188216390Sjchandra	}
189216390Sjchandra	if(xlr_board_info.xlr_i2c_device[I2C_RTC].enabled == 1) {
190216390Sjchandra		tmpd = device_add_child(sc->iicbus, "ds1374u", 0);
191216390Sjchandra		device_set_ivars(tmpd, &xlr_board_info.xlr_i2c_device[I2C_RTC]);
192216390Sjchandra	}
193216390Sjchandra	if(xlr_board_info.xlr_i2c_device[I2C_THERMAL].enabled == 1) {
194216390Sjchandra		tmpd = device_add_child(sc->iicbus, "max6657", 0);
195216390Sjchandra		device_set_ivars(tmpd, &xlr_board_info.xlr_i2c_device[I2C_THERMAL]);
196216390Sjchandra	}
197216390Sjchandra	if(xlr_board_info.xlr_i2c_device[I2C_EEPROM].enabled == 1) {
198216390Sjchandra		tmpd = device_add_child(sc->iicbus, "at24co2n", 0);
199216390Sjchandra		device_set_ivars(tmpd, &xlr_board_info.xlr_i2c_device[I2C_EEPROM]);
200216390Sjchandra	}
201198160Srrs
202198160Srrs	bus_generic_attach(dev);
203198160Srrs
204198625Srrs	return (0);
205198160Srrs}
206198625Srrs
207198160Srrsstatic int
208198160Srrsxlr_i2c_detach(device_t dev)
209198160Srrs{
210198160Srrs	bus_generic_detach(dev);
211198625Srrs
212198160Srrs	return (0);
213198160Srrs}
214198160Srrs
215198625Srrsstatic int
216198625Srrsxlr_i2c_start(device_t dev, u_char slave, int timeout)
217198160Srrs{
218198625Srrs	int error = 0;
219198625Srrs	struct xlr_i2c_softc *sc;
220198160Srrs
221198625Srrs	sc = device_get_softc(dev);
222216390Sjchandra        mtx_lock(&sc->sc_mtx);
223198625Srrs	sc->sc_started = 1;
224216390Sjchandra	sc->i2cdev_addr = (slave >> 1);
225198625Srrs	return error;
226198160Srrs
227198160Srrs}
228198160Srrs
229198625Srrsstatic int
230198625Srrsxlr_i2c_stop(device_t dev)
231198160Srrs{
232198625Srrs	int error = 0;
233216390Sjchandra	struct xlr_i2c_softc *sc;
234198160Srrs
235216390Sjchandra	sc = device_get_softc(dev);
236216390Sjchandra	mtx_unlock(&sc->sc_mtx);
237198625Srrs	return error;
238198160Srrs
239198160Srrs}
240198160Srrs
241198625Srrsstatic int
242198625Srrsxlr_i2c_read(device_t dev, char *buf, int len, int *read, int last,
243198625Srrs    int delay)
244198160Srrs{
245216390Sjchandra	volatile uint32_t i2c_status = 0;
246216390Sjchandra	int pos=0;
247216390Sjchandra	int timeout = 0;
248216390Sjchandra
249216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
250216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_BYTECNT, len);
251198160Srrs
252216390Sjchandraretry:
253216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
254198160Srrs
255216390Sjchandra	timeout = 0;
256216390Sjchandra	while(1) {
257216390Sjchandra		if(timeout++ > MAXTIME)
258216390Sjchandra			return -1;
259216390Sjchandra
260216390Sjchandra		i2c_status = xlr_i2c_dev_read(dev, XLR_I2C_STATUS);
261216390Sjchandra		if (i2c_status & XLR_I2C_RXRDY)
262216390Sjchandra			buf[pos++] = (uint8_t) xlr_i2c_dev_read(dev, XLR_I2C_DATAIN);
263216390Sjchandra
264216390Sjchandra		/* ACKERR -- bail */
265216390Sjchandra		if (i2c_status & XLR_I2C_ACK_ERR)
266216390Sjchandra			 return -1;      /* ACK_ERROR */
267216390Sjchandra
268216390Sjchandra		/* LOST ARB or STARTERR -- repeat */
269216390Sjchandra		if (i2c_status & XLR_I2C_ARB_STARTERR)
270216390Sjchandra			goto retry;
271216390Sjchandra
272216390Sjchandra		/* Wait for busy bit to go away */
273216390Sjchandra		if (i2c_status & XLR_I2C_BUS_BUSY)
274216390Sjchandra			continue;
275216390Sjchandra
276216390Sjchandra		if (pos == len)
277216390Sjchandra			break;
278216390Sjchandra	}
279216390Sjchandra	*read = pos;
280216390Sjchandra	return 0;
281216390Sjchandra
282198160Srrs}
283198160Srrs
284198625Srrsstatic int
285216390Sjchandraxlr_i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */ )
286198160Srrs{
287216390Sjchandra	volatile uint32_t i2c_status = 0x00;
288216390Sjchandra	uint8_t devaddr, addr;
289216390Sjchandra	struct xlr_i2c_softc *sc;
290216390Sjchandra	int pos;
291198160Srrs
292216390Sjchandra	sc = device_get_softc(dev);
293198160Srrs
294216390Sjchandra	/* the first byte of write is  addr (of register in device) */
295216390Sjchandra	addr = buf[0];
296216390Sjchandra	devaddr = sc->i2cdev_addr;
297216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_ADDR, addr);
298216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_DEVADDR, devaddr);
299216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
300216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_BYTECNT, len - 1);
301216390Sjchandra
302216390Sjchandraretry:
303216390Sjchandra	pos = 1;
304216390Sjchandra	if (len == 1) /* there is no data only address */
305216390Sjchandra		xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_ND);
306216390Sjchandra	else {
307216390Sjchandra		xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_WR);
308216390Sjchandra		xlr_i2c_dev_write(dev, XLR_I2C_DATAOUT, buf[pos]);
309198625Srrs	}
310198160Srrs
311216390Sjchandra	while (1) {
312216390Sjchandra		i2c_status = xlr_i2c_dev_read(dev, XLR_I2C_STATUS);
313216390Sjchandra
314216390Sjchandra		/* sdo empty send next byte */
315216390Sjchandra		if (i2c_status & XLR_I2C_SDOEMPTY) {
316216390Sjchandra			pos++;
317216390Sjchandra			xlr_i2c_dev_write(dev, XLR_I2C_DATAOUT, buf[pos]);
318216390Sjchandra		}
319198160Srrs
320216390Sjchandra		/* LOST ARB or STARTERR -- repeat */
321216390Sjchandra		if (i2c_status & XLR_I2C_ARB_STARTERR)
322216390Sjchandra			goto retry;
323198160Srrs
324216390Sjchandra		/* ACKERR -- bail */
325216390Sjchandra		if (i2c_status & XLR_I2C_ACK_ERR) {
326216390Sjchandra			printf("ACK ERR : exiting\n ");
327216390Sjchandra			return -1;
328216390Sjchandra		}
329216390Sjchandra
330216390Sjchandra		/* busy try again */
331216390Sjchandra		if (i2c_status & XLR_I2C_BUS_BUSY)
332216390Sjchandra			continue;
333198625Srrs
334216390Sjchandra		if (pos >= len)
335241844Seadler			break;
336216390Sjchandra	}
337216390Sjchandra	*sent = len - 1;
338216390Sjchandra	return 0;
339198160Srrs}
340198160Srrs
341216390Sjchandra
342216390Sjchandra
343198160Srrsstatic int
344216390Sjchandraxlr_i2c_callback(device_t dev, int index, caddr_t data)
345198160Srrs{
346198625Srrs	return 0;
347198160Srrs}
348198160Srrs
349198160Srrsstatic int
350198160Srrsxlr_i2c_repeated_start(device_t dev, u_char slave, int timeout)
351198160Srrs{
352198625Srrs	return 0;
353198160Srrs}
354198160Srrs
355216390Sjchandra/*
356216390Sjchandra * I2C bus transfer for RMI boards and devices.
357216390Sjchandra * Generic version of iicbus_transfer that calls the appropriate
358216390Sjchandra * routines to accomplish this.  See note above about acceptable
359216390Sjchandra * buffer addresses.
360216390Sjchandra */
361216390Sjchandraint
362216390Sjchandraxlr_i2c_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
363216390Sjchandra{
364216390Sjchandra        int i, error, lenread, lenwrote;
365216390Sjchandra        u_char addr;
366216390Sjchandra
367216390Sjchandra	addr = msgs[0].slave | LSB;
368216390Sjchandra	error = xlr_i2c_start(bus, addr, 0);
369216390Sjchandra        for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
370216390Sjchandra                if (msgs[i].flags & IIC_M_RD) {
371216390Sjchandra		        error = xlr_i2c_read((bus), msgs[i].buf, msgs[i].len, &lenread, IIC_LAST_READ, 0);
372216390Sjchandra		}
373216390Sjchandra                else {
374216390Sjchandra		        error = xlr_i2c_write((bus), msgs[i].buf, msgs[i].len, &lenwrote, 0);
375216390Sjchandra		}
376216390Sjchandra        }
377216390Sjchandra	error = xlr_i2c_stop(bus);
378216390Sjchandra        return (error);
379216390Sjchandra}
380198160Srrs
381216390Sjchandra
382198160Srrsstatic device_method_t xlr_i2c_methods[] = {
383198625Srrs	/* device interface */
384198625Srrs	DEVMETHOD(device_probe, xlr_i2c_probe),
385198625Srrs	DEVMETHOD(device_attach, xlr_i2c_attach),
386198625Srrs	DEVMETHOD(device_detach, xlr_i2c_detach),
387198160Srrs
388198625Srrs	/* iicbus interface */
389198625Srrs	DEVMETHOD(iicbus_callback, xlr_i2c_callback),
390198625Srrs	DEVMETHOD(iicbus_repeated_start, xlr_i2c_repeated_start),
391198625Srrs	DEVMETHOD(iicbus_start, xlr_i2c_start),
392198625Srrs	DEVMETHOD(iicbus_stop, xlr_i2c_stop),
393198625Srrs	DEVMETHOD(iicbus_write, xlr_i2c_write),
394198625Srrs	DEVMETHOD(iicbus_read, xlr_i2c_read),
395216390Sjchandra	DEVMETHOD(iicbus_transfer, xlr_i2c_transfer),
396198625Srrs	{0, 0}
397198160Srrs};
398198160Srrs
399198160Srrsstatic driver_t xlr_i2c_driver = {
400198625Srrs	"xlr_i2c",
401198625Srrs	xlr_i2c_methods,
402198625Srrs	sizeof(struct xlr_i2c_softc),
403198160Srrs};
404198160Srrs
405198160SrrsDRIVER_MODULE(xlr_i2c, iodi, xlr_i2c_driver, xlr_i2c_devclass, 0, 0);
406216390SjchandraDRIVER_MODULE(iicbus, xlr_i2c, iicbus_driver, iicbus_devclass, 0, 0);
407