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: stable/11/sys/mips/rmi/xlr_i2c.c 323467 2017-09-11 22:21:15Z ian $");
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) {
190323467Sian		tmpd = device_add_child(sc->iicbus, "ds13rtc", 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
202323467Sian	/*
203323467Sian	 * The old ds1374 rtc driver only handled one chip type.  The new
204323467Sian	 * ds13rtc driver handles all ds13xx chips, but must be told the chip
205323467Sian	 * type via hints.  XLR historically hasn't had a standard hints file,
206323467Sian	 * so set up the hint now if it isn't already there.
207323467Sian	 */
208323467Sian#define HINTNAME "hint.ds13rtc.0.compatible"
209323467Sian	if (!testenv(HINTNAME))
210323467Sian		kern_setenv(HINTNAME, "dallas,ds1374");
211323467Sian
212198160Srrs	bus_generic_attach(dev);
213198160Srrs
214198625Srrs	return (0);
215198160Srrs}
216198625Srrs
217198160Srrsstatic int
218198160Srrsxlr_i2c_detach(device_t dev)
219198160Srrs{
220198160Srrs	bus_generic_detach(dev);
221198625Srrs
222198160Srrs	return (0);
223198160Srrs}
224198160Srrs
225198625Srrsstatic int
226198625Srrsxlr_i2c_start(device_t dev, u_char slave, int timeout)
227198160Srrs{
228198625Srrs	int error = 0;
229198625Srrs	struct xlr_i2c_softc *sc;
230198160Srrs
231198625Srrs	sc = device_get_softc(dev);
232216390Sjchandra        mtx_lock(&sc->sc_mtx);
233198625Srrs	sc->sc_started = 1;
234216390Sjchandra	sc->i2cdev_addr = (slave >> 1);
235198625Srrs	return error;
236198160Srrs
237198160Srrs}
238198160Srrs
239198625Srrsstatic int
240198625Srrsxlr_i2c_stop(device_t dev)
241198160Srrs{
242198625Srrs	int error = 0;
243216390Sjchandra	struct xlr_i2c_softc *sc;
244198160Srrs
245216390Sjchandra	sc = device_get_softc(dev);
246216390Sjchandra	mtx_unlock(&sc->sc_mtx);
247198625Srrs	return error;
248198160Srrs
249198160Srrs}
250198160Srrs
251198625Srrsstatic int
252198625Srrsxlr_i2c_read(device_t dev, char *buf, int len, int *read, int last,
253198625Srrs    int delay)
254198160Srrs{
255216390Sjchandra	volatile uint32_t i2c_status = 0;
256216390Sjchandra	int pos=0;
257216390Sjchandra	int timeout = 0;
258216390Sjchandra
259216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
260216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_BYTECNT, len);
261198160Srrs
262216390Sjchandraretry:
263216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
264198160Srrs
265216390Sjchandra	timeout = 0;
266216390Sjchandra	while(1) {
267216390Sjchandra		if(timeout++ > MAXTIME)
268216390Sjchandra			return -1;
269216390Sjchandra
270216390Sjchandra		i2c_status = xlr_i2c_dev_read(dev, XLR_I2C_STATUS);
271216390Sjchandra		if (i2c_status & XLR_I2C_RXRDY)
272216390Sjchandra			buf[pos++] = (uint8_t) xlr_i2c_dev_read(dev, XLR_I2C_DATAIN);
273216390Sjchandra
274216390Sjchandra		/* ACKERR -- bail */
275216390Sjchandra		if (i2c_status & XLR_I2C_ACK_ERR)
276216390Sjchandra			 return -1;      /* ACK_ERROR */
277216390Sjchandra
278216390Sjchandra		/* LOST ARB or STARTERR -- repeat */
279216390Sjchandra		if (i2c_status & XLR_I2C_ARB_STARTERR)
280216390Sjchandra			goto retry;
281216390Sjchandra
282216390Sjchandra		/* Wait for busy bit to go away */
283216390Sjchandra		if (i2c_status & XLR_I2C_BUS_BUSY)
284216390Sjchandra			continue;
285216390Sjchandra
286216390Sjchandra		if (pos == len)
287216390Sjchandra			break;
288216390Sjchandra	}
289216390Sjchandra	*read = pos;
290216390Sjchandra	return 0;
291216390Sjchandra
292198160Srrs}
293198160Srrs
294198625Srrsstatic int
295216390Sjchandraxlr_i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */ )
296198160Srrs{
297216390Sjchandra	volatile uint32_t i2c_status = 0x00;
298216390Sjchandra	uint8_t devaddr, addr;
299216390Sjchandra	struct xlr_i2c_softc *sc;
300216390Sjchandra	int pos;
301198160Srrs
302216390Sjchandra	sc = device_get_softc(dev);
303198160Srrs
304216390Sjchandra	/* the first byte of write is  addr (of register in device) */
305216390Sjchandra	addr = buf[0];
306216390Sjchandra	devaddr = sc->i2cdev_addr;
307216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_ADDR, addr);
308216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_DEVADDR, devaddr);
309216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
310216390Sjchandra	xlr_i2c_dev_write(dev, XLR_I2C_BYTECNT, len - 1);
311216390Sjchandra
312216390Sjchandraretry:
313216390Sjchandra	pos = 1;
314216390Sjchandra	if (len == 1) /* there is no data only address */
315216390Sjchandra		xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_ND);
316216390Sjchandra	else {
317216390Sjchandra		xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_WR);
318216390Sjchandra		xlr_i2c_dev_write(dev, XLR_I2C_DATAOUT, buf[pos]);
319198625Srrs	}
320198160Srrs
321216390Sjchandra	while (1) {
322216390Sjchandra		i2c_status = xlr_i2c_dev_read(dev, XLR_I2C_STATUS);
323216390Sjchandra
324216390Sjchandra		/* sdo empty send next byte */
325216390Sjchandra		if (i2c_status & XLR_I2C_SDOEMPTY) {
326216390Sjchandra			pos++;
327216390Sjchandra			xlr_i2c_dev_write(dev, XLR_I2C_DATAOUT, buf[pos]);
328216390Sjchandra		}
329198160Srrs
330216390Sjchandra		/* LOST ARB or STARTERR -- repeat */
331216390Sjchandra		if (i2c_status & XLR_I2C_ARB_STARTERR)
332216390Sjchandra			goto retry;
333198160Srrs
334216390Sjchandra		/* ACKERR -- bail */
335216390Sjchandra		if (i2c_status & XLR_I2C_ACK_ERR) {
336216390Sjchandra			printf("ACK ERR : exiting\n ");
337216390Sjchandra			return -1;
338216390Sjchandra		}
339216390Sjchandra
340216390Sjchandra		/* busy try again */
341216390Sjchandra		if (i2c_status & XLR_I2C_BUS_BUSY)
342216390Sjchandra			continue;
343198625Srrs
344216390Sjchandra		if (pos >= len)
345241844Seadler			break;
346216390Sjchandra	}
347216390Sjchandra	*sent = len - 1;
348216390Sjchandra	return 0;
349198160Srrs}
350198160Srrs
351216390Sjchandra
352216390Sjchandra
353198160Srrsstatic int
354216390Sjchandraxlr_i2c_callback(device_t dev, int index, caddr_t data)
355198160Srrs{
356198625Srrs	return 0;
357198160Srrs}
358198160Srrs
359198160Srrsstatic int
360198160Srrsxlr_i2c_repeated_start(device_t dev, u_char slave, int timeout)
361198160Srrs{
362198625Srrs	return 0;
363198160Srrs}
364198160Srrs
365216390Sjchandra/*
366216390Sjchandra * I2C bus transfer for RMI boards and devices.
367216390Sjchandra * Generic version of iicbus_transfer that calls the appropriate
368216390Sjchandra * routines to accomplish this.  See note above about acceptable
369216390Sjchandra * buffer addresses.
370216390Sjchandra */
371216390Sjchandraint
372216390Sjchandraxlr_i2c_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
373216390Sjchandra{
374216390Sjchandra        int i, error, lenread, lenwrote;
375216390Sjchandra        u_char addr;
376216390Sjchandra
377216390Sjchandra	addr = msgs[0].slave | LSB;
378216390Sjchandra	error = xlr_i2c_start(bus, addr, 0);
379216390Sjchandra        for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
380216390Sjchandra                if (msgs[i].flags & IIC_M_RD) {
381216390Sjchandra		        error = xlr_i2c_read((bus), msgs[i].buf, msgs[i].len, &lenread, IIC_LAST_READ, 0);
382216390Sjchandra		}
383216390Sjchandra                else {
384216390Sjchandra		        error = xlr_i2c_write((bus), msgs[i].buf, msgs[i].len, &lenwrote, 0);
385216390Sjchandra		}
386216390Sjchandra        }
387216390Sjchandra	error = xlr_i2c_stop(bus);
388216390Sjchandra        return (error);
389216390Sjchandra}
390198160Srrs
391216390Sjchandra
392198160Srrsstatic device_method_t xlr_i2c_methods[] = {
393198625Srrs	/* device interface */
394198625Srrs	DEVMETHOD(device_probe, xlr_i2c_probe),
395198625Srrs	DEVMETHOD(device_attach, xlr_i2c_attach),
396198625Srrs	DEVMETHOD(device_detach, xlr_i2c_detach),
397198160Srrs
398198625Srrs	/* iicbus interface */
399198625Srrs	DEVMETHOD(iicbus_callback, xlr_i2c_callback),
400198625Srrs	DEVMETHOD(iicbus_repeated_start, xlr_i2c_repeated_start),
401198625Srrs	DEVMETHOD(iicbus_start, xlr_i2c_start),
402198625Srrs	DEVMETHOD(iicbus_stop, xlr_i2c_stop),
403198625Srrs	DEVMETHOD(iicbus_write, xlr_i2c_write),
404198625Srrs	DEVMETHOD(iicbus_read, xlr_i2c_read),
405216390Sjchandra	DEVMETHOD(iicbus_transfer, xlr_i2c_transfer),
406198625Srrs	{0, 0}
407198160Srrs};
408198160Srrs
409198160Srrsstatic driver_t xlr_i2c_driver = {
410198625Srrs	"xlr_i2c",
411198625Srrs	xlr_i2c_methods,
412198625Srrs	sizeof(struct xlr_i2c_softc),
413198160Srrs};
414198160Srrs
415198160SrrsDRIVER_MODULE(xlr_i2c, iodi, xlr_i2c_driver, xlr_i2c_devclass, 0, 0);
416216390SjchandraDRIVER_MODULE(iicbus, xlr_i2c, iicbus_driver, iicbus_devclass, 0, 0);
417