xref: /minix3/minix/drivers/bus/i2c/arch/earm/omap_i2c.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*
2*433d6423SLionel Sambuc  * This file implements support for i2c on the BeagleBone and BeagleBoard-xM
3*433d6423SLionel Sambuc  */
4*433d6423SLionel Sambuc 
5*433d6423SLionel Sambuc /* kernel headers */
6*433d6423SLionel Sambuc #include <minix/chardriver.h>
7*433d6423SLionel Sambuc #include <minix/clkconf.h>
8*433d6423SLionel Sambuc #include <minix/drivers.h>
9*433d6423SLionel Sambuc #include <minix/ds.h>
10*433d6423SLionel Sambuc #include <minix/log.h>
11*433d6423SLionel Sambuc #include <minix/mmio.h>
12*433d6423SLionel Sambuc #include <minix/padconf.h>
13*433d6423SLionel Sambuc #include <minix/sysutil.h>
14*433d6423SLionel Sambuc #include <minix/type.h>
15*433d6423SLionel Sambuc #include <minix/board.h>
16*433d6423SLionel Sambuc #include <minix/spin.h>
17*433d6423SLionel Sambuc 
18*433d6423SLionel Sambuc /* device headers */
19*433d6423SLionel Sambuc #include <minix/i2c.h>
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc /* system headers */
22*433d6423SLionel Sambuc #include <sys/ioctl.h>
23*433d6423SLionel Sambuc #include <sys/mman.h>
24*433d6423SLionel Sambuc #include <sys/types.h>
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc /* usr headers */
27*433d6423SLionel Sambuc #include <string.h>
28*433d6423SLionel Sambuc #include <stdio.h>
29*433d6423SLionel Sambuc #include <stdlib.h>
30*433d6423SLionel Sambuc 
31*433d6423SLionel Sambuc /* local headers */
32*433d6423SLionel Sambuc #include "omap_i2c.h"
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc /*
35*433d6423SLionel Sambuc  * defines the set of register
36*433d6423SLionel Sambuc  *
37*433d6423SLionel Sambuc  * Warning: always use the 16-bit variants of read/write/set from mmio.h
38*433d6423SLionel Sambuc  * to access these registers. The DM37XX TRM Section 17.6 warns that 32-bit
39*433d6423SLionel Sambuc  * accesses can corrupt the register contents.
40*433d6423SLionel Sambuc  */
41*433d6423SLionel Sambuc typedef struct omap_i2c_registers
42*433d6423SLionel Sambuc {
43*433d6423SLionel Sambuc 	vir_bytes I2C_REVNB_LO;	/* AM335X Only */
44*433d6423SLionel Sambuc 	vir_bytes I2C_REVNB_HI;	/* AM335X Only */
45*433d6423SLionel Sambuc 	vir_bytes I2C_REV;	/* DM37XX Only */
46*433d6423SLionel Sambuc 	vir_bytes I2C_IE;	/* DM37XX Only */
47*433d6423SLionel Sambuc 	vir_bytes I2C_STAT;	/* DM37XX Only */
48*433d6423SLionel Sambuc 	vir_bytes I2C_SYSC;
49*433d6423SLionel Sambuc 	vir_bytes I2C_IRQSTATUS_RAW;	/* AM335X Only */
50*433d6423SLionel Sambuc 	vir_bytes I2C_IRQSTATUS;	/* AM335X Only */
51*433d6423SLionel Sambuc 	vir_bytes I2C_IRQENABLE_SET;	/* AM335X Only */
52*433d6423SLionel Sambuc 	vir_bytes I2C_IRQENABLE_CLR;	/* AM335X Only */
53*433d6423SLionel Sambuc 	vir_bytes I2C_WE;
54*433d6423SLionel Sambuc 	vir_bytes I2C_DMARXENABLE_SET;	/* AM335X Only */
55*433d6423SLionel Sambuc 	vir_bytes I2C_DMATXENABLE_SET;	/* AM335X Only */
56*433d6423SLionel Sambuc 	vir_bytes I2C_DMARXENABLE_CLR;	/* AM335X Only */
57*433d6423SLionel Sambuc 	vir_bytes I2C_DMATXENABLE_CLR;	/* AM335X Only */
58*433d6423SLionel Sambuc 	vir_bytes I2C_DMARXWAKE_EN;	/* AM335X Only */
59*433d6423SLionel Sambuc 	vir_bytes I2C_DMATXWAKE_EN;	/* AM335X Only */
60*433d6423SLionel Sambuc 	vir_bytes I2C_SYSS;
61*433d6423SLionel Sambuc 	vir_bytes I2C_BUF;
62*433d6423SLionel Sambuc 	vir_bytes I2C_CNT;
63*433d6423SLionel Sambuc 	vir_bytes I2C_DATA;
64*433d6423SLionel Sambuc 	vir_bytes I2C_CON;
65*433d6423SLionel Sambuc 	vir_bytes I2C_OA;	/* AM335X Only */
66*433d6423SLionel Sambuc 	vir_bytes I2C_OA0;	/* DM37XX Only */
67*433d6423SLionel Sambuc 	vir_bytes I2C_SA;
68*433d6423SLionel Sambuc 	vir_bytes I2C_PSC;
69*433d6423SLionel Sambuc 	vir_bytes I2C_SCLL;
70*433d6423SLionel Sambuc 	vir_bytes I2C_SCLH;
71*433d6423SLionel Sambuc 	vir_bytes I2C_SYSTEST;
72*433d6423SLionel Sambuc 	vir_bytes I2C_BUFSTAT;
73*433d6423SLionel Sambuc 	vir_bytes I2C_OA1;
74*433d6423SLionel Sambuc 	vir_bytes I2C_OA2;
75*433d6423SLionel Sambuc 	vir_bytes I2C_OA3;
76*433d6423SLionel Sambuc 	vir_bytes I2C_ACTOA;
77*433d6423SLionel Sambuc 	vir_bytes I2C_SBLOCK;
78*433d6423SLionel Sambuc } omap_i2c_regs_t;
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc /* generic definition an i2c bus */
81*433d6423SLionel Sambuc 
82*433d6423SLionel Sambuc typedef struct omap_i2c_bus
83*433d6423SLionel Sambuc {
84*433d6423SLionel Sambuc 	enum bus_types
85*433d6423SLionel Sambuc 	{ AM335X_I2C_BUS, DM37XX_I2C_BUS} bus_type;
86*433d6423SLionel Sambuc 	phys_bytes mr_base;
87*433d6423SLionel Sambuc 	phys_bytes mr_size;
88*433d6423SLionel Sambuc 	vir_bytes mapped_addr;
89*433d6423SLionel Sambuc 	omap_i2c_regs_t *regs;
90*433d6423SLionel Sambuc 	uint32_t functional_clock;
91*433d6423SLionel Sambuc 	uint32_t module_clock;
92*433d6423SLionel Sambuc 	uint32_t bus_speed;
93*433d6423SLionel Sambuc 	uint16_t major;
94*433d6423SLionel Sambuc 	uint16_t minor;
95*433d6423SLionel Sambuc 	int irq;
96*433d6423SLionel Sambuc 	int irq_hook_id;
97*433d6423SLionel Sambuc 	int irq_hook_kernel_id;
98*433d6423SLionel Sambuc } omap_i2c_bus_t;
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc /* Define the registers for each chip */
101*433d6423SLionel Sambuc 
102*433d6423SLionel Sambuc static omap_i2c_regs_t am335x_i2c_regs = {
103*433d6423SLionel Sambuc 	.I2C_REVNB_LO = AM335X_I2C_REVNB_LO,
104*433d6423SLionel Sambuc 	.I2C_REVNB_HI = AM335X_I2C_REVNB_HI,
105*433d6423SLionel Sambuc 	.I2C_SYSC = AM335X_I2C_SYSC,
106*433d6423SLionel Sambuc 	.I2C_IRQSTATUS_RAW = AM335X_I2C_IRQSTATUS_RAW,
107*433d6423SLionel Sambuc 	.I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS,
108*433d6423SLionel Sambuc 	.I2C_IRQENABLE_SET = AM335X_I2C_IRQENABLE_SET,
109*433d6423SLionel Sambuc 	.I2C_IRQENABLE_CLR = AM335X_I2C_IRQENABLE_CLR,
110*433d6423SLionel Sambuc 	.I2C_WE = AM335X_I2C_WE,
111*433d6423SLionel Sambuc 	.I2C_DMARXENABLE_SET = AM335X_I2C_DMARXENABLE_SET,
112*433d6423SLionel Sambuc 	.I2C_DMATXENABLE_SET = AM335X_I2C_DMATXENABLE_SET,
113*433d6423SLionel Sambuc 	.I2C_DMARXENABLE_CLR = AM335X_I2C_DMARXENABLE_CLR,
114*433d6423SLionel Sambuc 	.I2C_DMATXENABLE_CLR = AM335X_I2C_DMATXENABLE_CLR,
115*433d6423SLionel Sambuc 	.I2C_DMARXWAKE_EN = AM335X_I2C_DMARXWAKE_EN,
116*433d6423SLionel Sambuc 	.I2C_DMATXWAKE_EN = AM335X_I2C_DMATXWAKE_EN,
117*433d6423SLionel Sambuc 	.I2C_SYSS = AM335X_I2C_SYSS,
118*433d6423SLionel Sambuc 	.I2C_BUF = AM335X_I2C_BUF,
119*433d6423SLionel Sambuc 	.I2C_CNT = AM335X_I2C_CNT,
120*433d6423SLionel Sambuc 	.I2C_DATA = AM335X_I2C_DATA,
121*433d6423SLionel Sambuc 	.I2C_CON = AM335X_I2C_CON,
122*433d6423SLionel Sambuc 	.I2C_OA = AM335X_I2C_OA,
123*433d6423SLionel Sambuc 	.I2C_SA = AM335X_I2C_SA,
124*433d6423SLionel Sambuc 	.I2C_PSC = AM335X_I2C_PSC,
125*433d6423SLionel Sambuc 	.I2C_SCLL = AM335X_I2C_SCLL,
126*433d6423SLionel Sambuc 	.I2C_SCLH = AM335X_I2C_SCLH,
127*433d6423SLionel Sambuc 	.I2C_SYSTEST = AM335X_I2C_SYSTEST,
128*433d6423SLionel Sambuc 	.I2C_BUFSTAT = AM335X_I2C_BUFSTAT,
129*433d6423SLionel Sambuc 	.I2C_OA1 = AM335X_I2C_OA1,
130*433d6423SLionel Sambuc 	.I2C_OA2 = AM335X_I2C_OA2,
131*433d6423SLionel Sambuc 	.I2C_OA3 = AM335X_I2C_OA3,
132*433d6423SLionel Sambuc 	.I2C_ACTOA = AM335X_I2C_ACTOA,
133*433d6423SLionel Sambuc 	.I2C_SBLOCK = AM335X_I2C_SBLOCK
134*433d6423SLionel Sambuc };
135*433d6423SLionel Sambuc 
136*433d6423SLionel Sambuc static omap_i2c_regs_t dm37xx_i2c_regs = {
137*433d6423SLionel Sambuc 	.I2C_REV = DM37XX_I2C_REV,
138*433d6423SLionel Sambuc 	.I2C_IE = DM37XX_I2C_IE,
139*433d6423SLionel Sambuc 	.I2C_STAT = DM37XX_I2C_STAT,
140*433d6423SLionel Sambuc 	.I2C_WE = DM37XX_I2C_WE,
141*433d6423SLionel Sambuc 	.I2C_SYSS = DM37XX_I2C_SYSS,
142*433d6423SLionel Sambuc 	.I2C_BUF = DM37XX_I2C_BUF,
143*433d6423SLionel Sambuc 	.I2C_CNT = DM37XX_I2C_CNT,
144*433d6423SLionel Sambuc 	.I2C_DATA = DM37XX_I2C_DATA,
145*433d6423SLionel Sambuc 	.I2C_SYSC = DM37XX_I2C_SYSC,
146*433d6423SLionel Sambuc 	.I2C_CON = DM37XX_I2C_CON,
147*433d6423SLionel Sambuc 	.I2C_OA0 = DM37XX_I2C_OA0,
148*433d6423SLionel Sambuc 	.I2C_SA = DM37XX_I2C_SA,
149*433d6423SLionel Sambuc 	.I2C_PSC = DM37XX_I2C_PSC,
150*433d6423SLionel Sambuc 	.I2C_SCLL = DM37XX_I2C_SCLL,
151*433d6423SLionel Sambuc 	.I2C_SCLH = DM37XX_I2C_SCLH,
152*433d6423SLionel Sambuc 	.I2C_SYSTEST = DM37XX_I2C_SYSTEST,
153*433d6423SLionel Sambuc 	.I2C_BUFSTAT = DM37XX_I2C_BUFSTAT,
154*433d6423SLionel Sambuc 	.I2C_OA1 = DM37XX_I2C_OA1,
155*433d6423SLionel Sambuc 	.I2C_OA2 = DM37XX_I2C_OA2,
156*433d6423SLionel Sambuc 	.I2C_OA3 = DM37XX_I2C_OA3,
157*433d6423SLionel Sambuc 	.I2C_ACTOA = DM37XX_I2C_ACTOA,
158*433d6423SLionel Sambuc 	.I2C_SBLOCK = DM37XX_I2C_SBLOCK
159*433d6423SLionel Sambuc };
160*433d6423SLionel Sambuc 
161*433d6423SLionel Sambuc /* Define the buses available on each chip */
162*433d6423SLionel Sambuc 
163*433d6423SLionel Sambuc static omap_i2c_bus_t am335x_i2c_buses[] = {
164*433d6423SLionel Sambuc 	{AM335X_I2C_BUS, AM335X_I2C0_BASE, AM335X_I2C0_SIZE, 0, &am335x_i2c_regs,
165*433d6423SLionel Sambuc 		    AM335X_FUNCTIONAL_CLOCK, AM335X_MODULE_CLOCK,
166*433d6423SLionel Sambuc 		    BUS_SPEED_400KHz, AM335X_REV_MAJOR, AM335X_REV_MINOR,
167*433d6423SLionel Sambuc 	    AM335X_I2C0_IRQ, 1, 1},
168*433d6423SLionel Sambuc 	{AM335X_I2C_BUS, AM335X_I2C1_BASE, AM335X_I2C1_SIZE, 0, &am335x_i2c_regs,
169*433d6423SLionel Sambuc 		    AM335X_FUNCTIONAL_CLOCK, AM335X_MODULE_CLOCK,
170*433d6423SLionel Sambuc 		    BUS_SPEED_100KHz, AM335X_REV_MAJOR, AM335X_REV_MINOR,
171*433d6423SLionel Sambuc 	    AM335X_I2C1_IRQ, 2, 3},
172*433d6423SLionel Sambuc 	{AM335X_I2C_BUS, AM335X_I2C2_BASE, AM335X_I2C2_SIZE, 0, &am335x_i2c_regs,
173*433d6423SLionel Sambuc 		    AM335X_FUNCTIONAL_CLOCK, AM335X_MODULE_CLOCK,
174*433d6423SLionel Sambuc 		    BUS_SPEED_100KHz, AM335X_REV_MAJOR, AM335X_REV_MINOR,
175*433d6423SLionel Sambuc 	    AM335X_I2C2_IRQ, 3, 3}
176*433d6423SLionel Sambuc };
177*433d6423SLionel Sambuc 
178*433d6423SLionel Sambuc #define AM335X_OMAP_NBUSES (sizeof(am335x_i2c_buses) / sizeof(omap_i2c_bus_t))
179*433d6423SLionel Sambuc 
180*433d6423SLionel Sambuc static omap_i2c_bus_t dm37xx_i2c_buses[] = {
181*433d6423SLionel Sambuc 	{DM37XX_I2C_BUS, DM37XX_I2C0_BASE, DM37XX_I2C0_SIZE, 0, &dm37xx_i2c_regs,
182*433d6423SLionel Sambuc 		    DM37XX_FUNCTIONAL_CLOCK, DM37XX_MODULE_CLOCK,
183*433d6423SLionel Sambuc 		    BUS_SPEED_100KHz, DM37XX_REV_MAJOR, DM37XX_REV_MINOR,
184*433d6423SLionel Sambuc 	    DM37XX_I2C0_IRQ, 1, 1},
185*433d6423SLionel Sambuc 	{DM37XX_I2C_BUS, DM37XX_I2C1_BASE, DM37XX_I2C1_SIZE, 0, &dm37xx_i2c_regs,
186*433d6423SLionel Sambuc 		    DM37XX_FUNCTIONAL_CLOCK, DM37XX_MODULE_CLOCK,
187*433d6423SLionel Sambuc 		    BUS_SPEED_100KHz, DM37XX_REV_MAJOR, DM37XX_REV_MINOR,
188*433d6423SLionel Sambuc 	    DM37XX_I2C1_IRQ, 2, 2},
189*433d6423SLionel Sambuc 	{DM37XX_I2C_BUS, DM37XX_I2C2_BASE, DM37XX_I2C2_SIZE, 0, &dm37xx_i2c_regs,
190*433d6423SLionel Sambuc 		    DM37XX_FUNCTIONAL_CLOCK, DM37XX_MODULE_CLOCK,
191*433d6423SLionel Sambuc 		    BUS_SPEED_100KHz, DM37XX_REV_MAJOR, DM37XX_REV_MINOR,
192*433d6423SLionel Sambuc 	    DM37XX_I2C2_IRQ, 3, 3}
193*433d6423SLionel Sambuc };
194*433d6423SLionel Sambuc 
195*433d6423SLionel Sambuc #define DM37XX_OMAP_NBUSES (sizeof(dm37xx_i2c_buses) / sizeof(omap_i2c_bus_t))
196*433d6423SLionel Sambuc 
197*433d6423SLionel Sambuc /* Globals */
198*433d6423SLionel Sambuc 
199*433d6423SLionel Sambuc static omap_i2c_bus_t *omap_i2c_buses;	/* all available buses for this SoC */
200*433d6423SLionel Sambuc static omap_i2c_bus_t *omap_i2c_bus;	/* the bus selected at start-up */
201*433d6423SLionel Sambuc static int omap_i2c_nbuses;	/* number of buses supported by SoC */
202*433d6423SLionel Sambuc 
203*433d6423SLionel Sambuc /* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
204*433d6423SLionel Sambuc static struct log log = {
205*433d6423SLionel Sambuc 	.name = "i2c",
206*433d6423SLionel Sambuc 	.log_level = LEVEL_INFO,
207*433d6423SLionel Sambuc 	.log_func = default_log
208*433d6423SLionel Sambuc };
209*433d6423SLionel Sambuc 
210*433d6423SLionel Sambuc /* Local Function Prototypes */
211*433d6423SLionel Sambuc 
212*433d6423SLionel Sambuc /* Implementation of Generic I2C Interface using Bus Specific Code */
213*433d6423SLionel Sambuc static int omap_i2c_process(minix_i2c_ioctl_exec_t * m);
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc /* Bus Specific Code */
216*433d6423SLionel Sambuc static void omap_i2c_flush(void);
217*433d6423SLionel Sambuc static uint16_t omap_i2c_poll(uint16_t mask);
218*433d6423SLionel Sambuc static int omap_i2c_bus_is_free(void);
219*433d6423SLionel Sambuc static int omap_i2c_soft_reset(void);
220*433d6423SLionel Sambuc static void omap_i2c_bus_init(void);
221*433d6423SLionel Sambuc static void omap_i2c_padconf(int i2c_bus_id);
222*433d6423SLionel Sambuc static void omap_i2c_clkconf(int i2c_bus_id);
223*433d6423SLionel Sambuc static void omap_i2c_intr_enable(void);
224*433d6423SLionel Sambuc static uint16_t omap_i2c_read_status(void);
225*433d6423SLionel Sambuc static void omap_i2c_write_status(uint16_t mask);
226*433d6423SLionel Sambuc static int omap_i2c_read(i2c_addr_t addr, uint8_t * buf, size_t buflen,
227*433d6423SLionel Sambuc     int dostop);
228*433d6423SLionel Sambuc static int omap_i2c_write(i2c_addr_t addr, const uint8_t * buf, size_t buflen,
229*433d6423SLionel Sambuc     int dostop);
230*433d6423SLionel Sambuc 
231*433d6423SLionel Sambuc /*
232*433d6423SLionel Sambuc  * Performs the action in minix_i2c_ioctl_exec_t.
233*433d6423SLionel Sambuc  */
234*433d6423SLionel Sambuc static int
omap_i2c_process(minix_i2c_ioctl_exec_t * ioctl_exec)235*433d6423SLionel Sambuc omap_i2c_process(minix_i2c_ioctl_exec_t * ioctl_exec)
236*433d6423SLionel Sambuc {
237*433d6423SLionel Sambuc 	int r;
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc 	/*
240*433d6423SLionel Sambuc 	 * Zero data bytes transfers are not allowed. The controller treats
241*433d6423SLionel Sambuc 	 * I2C_CNT register value of 0x0 as 65536. This is true for both the
242*433d6423SLionel Sambuc 	 * am335x and dm37xx. Full details in the TRM on the I2C_CNT page.
243*433d6423SLionel Sambuc 	 */
244*433d6423SLionel Sambuc 	if (ioctl_exec->iie_buflen == 0) {
245*433d6423SLionel Sambuc 		return EINVAL;
246*433d6423SLionel Sambuc 	}
247*433d6423SLionel Sambuc 
248*433d6423SLionel Sambuc 	omap_i2c_flush();	/* clear any garbage in the fifo */
249*433d6423SLionel Sambuc 
250*433d6423SLionel Sambuc 	/* Check bus busy flag before using the bus */
251*433d6423SLionel Sambuc 	r = omap_i2c_bus_is_free();
252*433d6423SLionel Sambuc 	if (r == 0) {
253*433d6423SLionel Sambuc 		log_warn(&log, "Bus is busy\n");
254*433d6423SLionel Sambuc 		return EBUSY;
255*433d6423SLionel Sambuc 	}
256*433d6423SLionel Sambuc 
257*433d6423SLionel Sambuc 	if (ioctl_exec->iie_cmdlen > 0) {
258*433d6423SLionel Sambuc 		r = omap_i2c_write(ioctl_exec->iie_addr, ioctl_exec->iie_cmd,
259*433d6423SLionel Sambuc 		    ioctl_exec->iie_cmdlen,
260*433d6423SLionel Sambuc 		    !(I2C_OP_READ_P(ioctl_exec->iie_op)));
261*433d6423SLionel Sambuc 		if (r != OK) {
262*433d6423SLionel Sambuc 			omap_i2c_soft_reset();
263*433d6423SLionel Sambuc 			omap_i2c_bus_init();
264*433d6423SLionel Sambuc 			return r;
265*433d6423SLionel Sambuc 		}
266*433d6423SLionel Sambuc 	}
267*433d6423SLionel Sambuc 
268*433d6423SLionel Sambuc 	if (I2C_OP_READ_P(ioctl_exec->iie_op)) {
269*433d6423SLionel Sambuc 		r = omap_i2c_read(ioctl_exec->iie_addr, ioctl_exec->iie_buf,
270*433d6423SLionel Sambuc 		    ioctl_exec->iie_buflen, I2C_OP_STOP_P(ioctl_exec->iie_op));
271*433d6423SLionel Sambuc 	} else {
272*433d6423SLionel Sambuc 		r = omap_i2c_write(ioctl_exec->iie_addr, ioctl_exec->iie_buf,
273*433d6423SLionel Sambuc 		    ioctl_exec->iie_buflen, I2C_OP_STOP_P(ioctl_exec->iie_op));
274*433d6423SLionel Sambuc 	}
275*433d6423SLionel Sambuc 
276*433d6423SLionel Sambuc 	if (r != OK) {
277*433d6423SLionel Sambuc 		omap_i2c_soft_reset();
278*433d6423SLionel Sambuc 		omap_i2c_bus_init();
279*433d6423SLionel Sambuc 		return r;
280*433d6423SLionel Sambuc 	}
281*433d6423SLionel Sambuc 
282*433d6423SLionel Sambuc 	return OK;
283*433d6423SLionel Sambuc }
284*433d6423SLionel Sambuc 
285*433d6423SLionel Sambuc /*
286*433d6423SLionel Sambuc  * Drain the incoming FIFO.
287*433d6423SLionel Sambuc  *
288*433d6423SLionel Sambuc  * Usually called to clear any garbage that may be in the buffer before
289*433d6423SLionel Sambuc  * doing a read.
290*433d6423SLionel Sambuc  */
291*433d6423SLionel Sambuc static void
omap_i2c_flush(void)292*433d6423SLionel Sambuc omap_i2c_flush(void)
293*433d6423SLionel Sambuc {
294*433d6423SLionel Sambuc 	int tries;
295*433d6423SLionel Sambuc 	int status;
296*433d6423SLionel Sambuc 
297*433d6423SLionel Sambuc 	for (tries = 0; tries < 1000; tries++) {
298*433d6423SLionel Sambuc 		status = omap_i2c_poll(1 << RRDY);
299*433d6423SLionel Sambuc 		if ((status & (1 << RRDY)) != 0) {	/* bytes available for reading */
300*433d6423SLionel Sambuc 
301*433d6423SLionel Sambuc 			/* consume the byte and throw it away */
302*433d6423SLionel Sambuc 			(void) read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_DATA);
303*433d6423SLionel Sambuc 
304*433d6423SLionel Sambuc 			/* clear the read ready flag */
305*433d6423SLionel Sambuc 			omap_i2c_write_status(1 << RRDY);
306*433d6423SLionel Sambuc 
307*433d6423SLionel Sambuc 		} else {
308*433d6423SLionel Sambuc 			break;	/* buffer drained */
309*433d6423SLionel Sambuc 		}
310*433d6423SLionel Sambuc 	}
311*433d6423SLionel Sambuc }
312*433d6423SLionel Sambuc 
313*433d6423SLionel Sambuc /*
314*433d6423SLionel Sambuc  * Poll the status register checking the bits set in 'mask'.
315*433d6423SLionel Sambuc  * Returns the status if any bits set or 0x0000 when the timeout is reached.
316*433d6423SLionel Sambuc  */
317*433d6423SLionel Sambuc static uint16_t
omap_i2c_poll(uint16_t mask)318*433d6423SLionel Sambuc omap_i2c_poll(uint16_t mask)
319*433d6423SLionel Sambuc {
320*433d6423SLionel Sambuc 	spin_t spin;
321*433d6423SLionel Sambuc 	uint16_t status;
322*433d6423SLionel Sambuc 
323*433d6423SLionel Sambuc 	/* poll for up to 1 s */
324*433d6423SLionel Sambuc 	spin_init(&spin, 1000000);
325*433d6423SLionel Sambuc 	do {
326*433d6423SLionel Sambuc 		status = omap_i2c_read_status();
327*433d6423SLionel Sambuc 		if ((status & mask) != 0) {	/* any bits in mask set */
328*433d6423SLionel Sambuc 			return status;
329*433d6423SLionel Sambuc 		}
330*433d6423SLionel Sambuc 
331*433d6423SLionel Sambuc 	} while (spin_check(&spin));
332*433d6423SLionel Sambuc 
333*433d6423SLionel Sambuc 	return status;		/* timeout reached, abort */
334*433d6423SLionel Sambuc }
335*433d6423SLionel Sambuc 
336*433d6423SLionel Sambuc /*
337*433d6423SLionel Sambuc  * Poll Bus Busy Flag until the bus becomes free (return 1) or the timeout
338*433d6423SLionel Sambuc  * expires (return 0).
339*433d6423SLionel Sambuc  */
340*433d6423SLionel Sambuc static int
omap_i2c_bus_is_free(void)341*433d6423SLionel Sambuc omap_i2c_bus_is_free(void)
342*433d6423SLionel Sambuc {
343*433d6423SLionel Sambuc 	spin_t spin;
344*433d6423SLionel Sambuc 	uint16_t status;
345*433d6423SLionel Sambuc 
346*433d6423SLionel Sambuc 	/* wait for up to 1 second for the bus to become free */
347*433d6423SLionel Sambuc 	spin_init(&spin, 1000000);
348*433d6423SLionel Sambuc 	do {
349*433d6423SLionel Sambuc 
350*433d6423SLionel Sambuc 		status = omap_i2c_read_status();
351*433d6423SLionel Sambuc 		if ((status & (1 << BB)) == 0) {
352*433d6423SLionel Sambuc 			return 1;	/* bus is free */
353*433d6423SLionel Sambuc 		}
354*433d6423SLionel Sambuc 
355*433d6423SLionel Sambuc 	} while (spin_check(&spin));
356*433d6423SLionel Sambuc 
357*433d6423SLionel Sambuc 	return 0;		/* timeout expired */
358*433d6423SLionel Sambuc }
359*433d6423SLionel Sambuc 
360*433d6423SLionel Sambuc static void
omap_i2c_clkconf(int i2c_bus_id)361*433d6423SLionel Sambuc omap_i2c_clkconf(int i2c_bus_id)
362*433d6423SLionel Sambuc {
363*433d6423SLionel Sambuc 	clkconf_init();
364*433d6423SLionel Sambuc 
365*433d6423SLionel Sambuc 	if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
366*433d6423SLionel Sambuc 
367*433d6423SLionel Sambuc 		clkconf_set(CM_ICLKEN1_CORE, BIT((15 + i2c_bus_id)),
368*433d6423SLionel Sambuc 		    0xffffffff);
369*433d6423SLionel Sambuc 		clkconf_set(CM_FCLKEN1_CORE, BIT((15 + i2c_bus_id)),
370*433d6423SLionel Sambuc 		    0xffffffff);
371*433d6423SLionel Sambuc 
372*433d6423SLionel Sambuc 	} else if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
373*433d6423SLionel Sambuc 
374*433d6423SLionel Sambuc 		switch (i2c_bus_id) {
375*433d6423SLionel Sambuc 		case 0:
376*433d6423SLionel Sambuc 			clkconf_set(CM_WKUP_I2C0_CLKCTRL, BIT(1), 0xffffffff);
377*433d6423SLionel Sambuc 			break;
378*433d6423SLionel Sambuc 		case 1:
379*433d6423SLionel Sambuc 			clkconf_set(CM_PER_I2C1_CLKCTRL, BIT(1), 0xffffffff);
380*433d6423SLionel Sambuc 			break;
381*433d6423SLionel Sambuc 		case 2:
382*433d6423SLionel Sambuc 			clkconf_set(CM_PER_I2C2_CLKCTRL, BIT(1), 0xffffffff);
383*433d6423SLionel Sambuc 			break;
384*433d6423SLionel Sambuc 		default:
385*433d6423SLionel Sambuc 			log_warn(&log, "Invalid i2c_bus_id\n");
386*433d6423SLionel Sambuc 			break;
387*433d6423SLionel Sambuc 		}
388*433d6423SLionel Sambuc 	}
389*433d6423SLionel Sambuc 
390*433d6423SLionel Sambuc 	clkconf_release();
391*433d6423SLionel Sambuc }
392*433d6423SLionel Sambuc 
393*433d6423SLionel Sambuc static void
omap_i2c_padconf(int i2c_bus_id)394*433d6423SLionel Sambuc omap_i2c_padconf(int i2c_bus_id)
395*433d6423SLionel Sambuc {
396*433d6423SLionel Sambuc 	int r;
397*433d6423SLionel Sambuc 	u32_t pinopts;
398*433d6423SLionel Sambuc 
399*433d6423SLionel Sambuc 	if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
400*433d6423SLionel Sambuc 
401*433d6423SLionel Sambuc 		/* use the options suggested in starterware driver */
402*433d6423SLionel Sambuc 		pinopts =
403*433d6423SLionel Sambuc 		    CONTROL_CONF_SLEWCTRL | CONTROL_CONF_RXACTIVE |
404*433d6423SLionel Sambuc 		    CONTROL_CONF_PUTYPESEL;
405*433d6423SLionel Sambuc 
406*433d6423SLionel Sambuc 		switch (i2c_bus_id) {
407*433d6423SLionel Sambuc 		case 0:
408*433d6423SLionel Sambuc 			pinopts |= CONTROL_CONF_MUXMODE(0);
409*433d6423SLionel Sambuc 
410*433d6423SLionel Sambuc 			r = sys_padconf(CONTROL_CONF_I2C0_SDA, 0xffffffff,
411*433d6423SLionel Sambuc 			    pinopts);
412*433d6423SLionel Sambuc 			if (r != OK) {
413*433d6423SLionel Sambuc 				log_warn(&log, "padconf failed (r=%d)\n", r);
414*433d6423SLionel Sambuc 			}
415*433d6423SLionel Sambuc 
416*433d6423SLionel Sambuc 			r = sys_padconf(CONTROL_CONF_I2C0_SCL, 0xffffffff,
417*433d6423SLionel Sambuc 			    pinopts);
418*433d6423SLionel Sambuc 			if (r != OK) {
419*433d6423SLionel Sambuc 				log_warn(&log, "padconf failed (r=%d)\n", r);
420*433d6423SLionel Sambuc 			}
421*433d6423SLionel Sambuc 
422*433d6423SLionel Sambuc 			log_debug(&log, "pinopts=0x%x\n", pinopts);
423*433d6423SLionel Sambuc 			break;
424*433d6423SLionel Sambuc 
425*433d6423SLionel Sambuc 		case 1:
426*433d6423SLionel Sambuc 			pinopts |= CONTROL_CONF_MUXMODE(2);
427*433d6423SLionel Sambuc 
428*433d6423SLionel Sambuc 			r = sys_padconf(CONTROL_CONF_SPI0_CS0, 0xffffffff,
429*433d6423SLionel Sambuc 			    pinopts);
430*433d6423SLionel Sambuc 			if (r != OK) {
431*433d6423SLionel Sambuc 				log_warn(&log, "padconf failed (r=%d)\n", r);
432*433d6423SLionel Sambuc 			}
433*433d6423SLionel Sambuc 
434*433d6423SLionel Sambuc 			r = sys_padconf(CONTROL_CONF_SPI0_D1, 0xffffffff,
435*433d6423SLionel Sambuc 			    pinopts);
436*433d6423SLionel Sambuc 			if (r != OK) {
437*433d6423SLionel Sambuc 				log_warn(&log, "padconf failed (r=%d)\n", r);
438*433d6423SLionel Sambuc 			}
439*433d6423SLionel Sambuc 			log_debug(&log, "pinopts=0x%x\n", pinopts);
440*433d6423SLionel Sambuc 			break;
441*433d6423SLionel Sambuc 
442*433d6423SLionel Sambuc 		case 2:
443*433d6423SLionel Sambuc 			pinopts |= CONTROL_CONF_MUXMODE(3);
444*433d6423SLionel Sambuc 
445*433d6423SLionel Sambuc 			r = sys_padconf(CONTROL_CONF_UART1_CTSN, 0xffffffff,
446*433d6423SLionel Sambuc 			    pinopts);
447*433d6423SLionel Sambuc 			if (r != OK) {
448*433d6423SLionel Sambuc 				log_warn(&log, "padconf failed (r=%d)\n", r);
449*433d6423SLionel Sambuc 			}
450*433d6423SLionel Sambuc 
451*433d6423SLionel Sambuc 			r = sys_padconf(CONTROL_CONF_UART1_RTSN,
452*433d6423SLionel Sambuc 			    0xffffffff, pinopts);
453*433d6423SLionel Sambuc 			if (r != OK) {
454*433d6423SLionel Sambuc 				log_warn(&log, "padconf failed (r=%d)\n", r);
455*433d6423SLionel Sambuc 			}
456*433d6423SLionel Sambuc 
457*433d6423SLionel Sambuc 			log_debug(&log, "pinopts=0x%x\n", pinopts);
458*433d6423SLionel Sambuc 			break;
459*433d6423SLionel Sambuc 
460*433d6423SLionel Sambuc 		default:
461*433d6423SLionel Sambuc 			log_warn(&log, "Invalid i2c_bus_id\n");
462*433d6423SLionel Sambuc 			break;
463*433d6423SLionel Sambuc 		}
464*433d6423SLionel Sambuc 	}
465*433d6423SLionel Sambuc 
466*433d6423SLionel Sambuc 	/* nothing to do for the DM37XX */
467*433d6423SLionel Sambuc }
468*433d6423SLionel Sambuc 
469*433d6423SLionel Sambuc static int
omap_i2c_soft_reset(void)470*433d6423SLionel Sambuc omap_i2c_soft_reset(void)
471*433d6423SLionel Sambuc {
472*433d6423SLionel Sambuc 	spin_t spin;
473*433d6423SLionel Sambuc 
474*433d6423SLionel Sambuc 	/* Disable to do soft reset */
475*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, 0);
476*433d6423SLionel Sambuc 	micro_delay(50000);
477*433d6423SLionel Sambuc 
478*433d6423SLionel Sambuc 	/* Do a soft reset */
479*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SYSC, (1 << SRST));
480*433d6423SLionel Sambuc 
481*433d6423SLionel Sambuc 	/* Have to temporarily enable I2C to read RDONE */
482*433d6423SLionel Sambuc 	set16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, (1<<I2C_EN), (1<<I2C_EN));
483*433d6423SLionel Sambuc 	micro_delay(50000);
484*433d6423SLionel Sambuc 
485*433d6423SLionel Sambuc 	/* wait up to 3 seconds for reset to complete */
486*433d6423SLionel Sambuc 	spin_init(&spin, 3000000);
487*433d6423SLionel Sambuc 	do {
488*433d6423SLionel Sambuc 		if (read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SYSS) & (1 << RDONE)) {
489*433d6423SLionel Sambuc 			return OK;
490*433d6423SLionel Sambuc 		}
491*433d6423SLionel Sambuc 
492*433d6423SLionel Sambuc 	} while (spin_check(&spin));
493*433d6423SLionel Sambuc 
494*433d6423SLionel Sambuc 	log_warn(&log, "Tried soft reset, but bus never came back.\n");
495*433d6423SLionel Sambuc 	return EIO;
496*433d6423SLionel Sambuc }
497*433d6423SLionel Sambuc 
498*433d6423SLionel Sambuc static void
omap_i2c_intr_enable(void)499*433d6423SLionel Sambuc omap_i2c_intr_enable(void)
500*433d6423SLionel Sambuc {
501*433d6423SLionel Sambuc 	int r;
502*433d6423SLionel Sambuc 	uint16_t intmask;
503*433d6423SLionel Sambuc 	static int policy_set = 0;
504*433d6423SLionel Sambuc 	static int enabled = 0;
505*433d6423SLionel Sambuc 
506*433d6423SLionel Sambuc 	if (!policy_set) {
507*433d6423SLionel Sambuc 		r = sys_irqsetpolicy(omap_i2c_bus->irq, 0,
508*433d6423SLionel Sambuc 		    &omap_i2c_bus->irq_hook_kernel_id);
509*433d6423SLionel Sambuc 		if (r == OK) {
510*433d6423SLionel Sambuc 			policy_set = 1;
511*433d6423SLionel Sambuc 		} else {
512*433d6423SLionel Sambuc 			log_warn(&log, "Couldn't set irq policy\n");
513*433d6423SLionel Sambuc 		}
514*433d6423SLionel Sambuc 	}
515*433d6423SLionel Sambuc 
516*433d6423SLionel Sambuc 	if (policy_set && !enabled) {
517*433d6423SLionel Sambuc 		r = sys_irqenable(&omap_i2c_bus->irq_hook_kernel_id);
518*433d6423SLionel Sambuc 		if (r == OK) {
519*433d6423SLionel Sambuc 			enabled = 1;
520*433d6423SLionel Sambuc 		} else {
521*433d6423SLionel Sambuc 			log_warn(&log, "Couldn't enable irq %d (hooked)\n",
522*433d6423SLionel Sambuc 			    omap_i2c_bus->irq);
523*433d6423SLionel Sambuc 		}
524*433d6423SLionel Sambuc 	}
525*433d6423SLionel Sambuc 
526*433d6423SLionel Sambuc 	/* According to NetBSD driver and u-boot, these are needed even
527*433d6423SLionel Sambuc 	 * if just using polling (i.e. non-interrupt driver programming).
528*433d6423SLionel Sambuc 	 */
529*433d6423SLionel Sambuc 	intmask = 0;
530*433d6423SLionel Sambuc 	intmask |= (1 << ROVR);
531*433d6423SLionel Sambuc 	intmask |= (1 << AERR);
532*433d6423SLionel Sambuc 	intmask |= (1 << XRDY);
533*433d6423SLionel Sambuc 	intmask |= (1 << RRDY);
534*433d6423SLionel Sambuc 	intmask |= (1 << ARDY);
535*433d6423SLionel Sambuc 	intmask |= (1 << NACK);
536*433d6423SLionel Sambuc 	intmask |= (1 << AL);
537*433d6423SLionel Sambuc 
538*433d6423SLionel Sambuc 	if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
539*433d6423SLionel Sambuc 		write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IRQENABLE_SET, intmask);
540*433d6423SLionel Sambuc 	} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
541*433d6423SLionel Sambuc 		write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IE, intmask);
542*433d6423SLionel Sambuc 	} else {
543*433d6423SLionel Sambuc 		log_warn(&log, "Don't know how to enable interrupts.\n");
544*433d6423SLionel Sambuc 	}
545*433d6423SLionel Sambuc }
546*433d6423SLionel Sambuc 
547*433d6423SLionel Sambuc static void
omap_i2c_bus_init(void)548*433d6423SLionel Sambuc omap_i2c_bus_init(void)
549*433d6423SLionel Sambuc {
550*433d6423SLionel Sambuc 
551*433d6423SLionel Sambuc 	/* Ensure i2c module is disabled before setting prescalar & bus speed */
552*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, 0);
553*433d6423SLionel Sambuc 	micro_delay(50000);
554*433d6423SLionel Sambuc 
555*433d6423SLionel Sambuc 	/* Disable autoidle */
556*433d6423SLionel Sambuc 	set16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SYSC, (1<<AUTOIDLE), (0<<AUTOIDLE));
557*433d6423SLionel Sambuc 
558*433d6423SLionel Sambuc 	/* Set prescalar to obtain 12 MHz i2c module clock */
559*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_PSC,
560*433d6423SLionel Sambuc 	    ((omap_i2c_bus->functional_clock / omap_i2c_bus->module_clock) -
561*433d6423SLionel Sambuc 		1));
562*433d6423SLionel Sambuc 
563*433d6423SLionel Sambuc 	/* Set the bus speed */
564*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SCLL,
565*433d6423SLionel Sambuc 	    ((omap_i2c_bus->module_clock / (2 * omap_i2c_bus->bus_speed)) -
566*433d6423SLionel Sambuc 		7));
567*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SCLH,
568*433d6423SLionel Sambuc 	    ((omap_i2c_bus->module_clock / (2 * omap_i2c_bus->bus_speed)) -
569*433d6423SLionel Sambuc 		5));
570*433d6423SLionel Sambuc 
571*433d6423SLionel Sambuc 	/* Set own I2C address */
572*433d6423SLionel Sambuc 	if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
573*433d6423SLionel Sambuc 		write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_OA, I2C_OWN_ADDRESS);
574*433d6423SLionel Sambuc 	} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
575*433d6423SLionel Sambuc 		write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_OA0, I2C_OWN_ADDRESS);
576*433d6423SLionel Sambuc 	} else {
577*433d6423SLionel Sambuc 		log_warn(&log, "Don't know how to set own address.\n");
578*433d6423SLionel Sambuc 	}
579*433d6423SLionel Sambuc 
580*433d6423SLionel Sambuc 	/* Set TX/RX Threshold to 1 and disable I2C DMA */
581*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_BUF, 0x0000);
582*433d6423SLionel Sambuc 
583*433d6423SLionel Sambuc 	/* Bring the i2c module out of reset */
584*433d6423SLionel Sambuc 	set16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, (1<<I2C_EN), (1<<I2C_EN));
585*433d6423SLionel Sambuc 	micro_delay(50000);
586*433d6423SLionel Sambuc 
587*433d6423SLionel Sambuc 	/*
588*433d6423SLionel Sambuc 	 * Enable interrupts
589*433d6423SLionel Sambuc 	 */
590*433d6423SLionel Sambuc 	omap_i2c_intr_enable();
591*433d6423SLionel Sambuc }
592*433d6423SLionel Sambuc 
593*433d6423SLionel Sambuc static uint16_t
omap_i2c_read_status(void)594*433d6423SLionel Sambuc omap_i2c_read_status(void)
595*433d6423SLionel Sambuc {
596*433d6423SLionel Sambuc 	uint16_t status = 0x0000;
597*433d6423SLionel Sambuc 
598*433d6423SLionel Sambuc 	if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
599*433d6423SLionel Sambuc 		/* TRM says to use RAW for polling for events */
600*433d6423SLionel Sambuc 		status = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IRQSTATUS_RAW);
601*433d6423SLionel Sambuc 	} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
602*433d6423SLionel Sambuc 		status = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_STAT);
603*433d6423SLionel Sambuc 	} else {
604*433d6423SLionel Sambuc 		log_warn(&log, "Don't know how to read i2c bus status.\n");
605*433d6423SLionel Sambuc 	}
606*433d6423SLionel Sambuc 
607*433d6423SLionel Sambuc 	return status;
608*433d6423SLionel Sambuc }
609*433d6423SLionel Sambuc 
610*433d6423SLionel Sambuc static void
omap_i2c_write_status(uint16_t mask)611*433d6423SLionel Sambuc omap_i2c_write_status(uint16_t mask)
612*433d6423SLionel Sambuc {
613*433d6423SLionel Sambuc 	if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
614*433d6423SLionel Sambuc 		/* write 1's to IRQSTATUS (not RAW) to clear the bits */
615*433d6423SLionel Sambuc 		write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IRQSTATUS, mask);
616*433d6423SLionel Sambuc 	} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
617*433d6423SLionel Sambuc 		write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_STAT, mask);
618*433d6423SLionel Sambuc 	} else {
619*433d6423SLionel Sambuc 		log_warn(&log, "Don't know how to clear i2c bus status.\n");
620*433d6423SLionel Sambuc 	}
621*433d6423SLionel Sambuc }
622*433d6423SLionel Sambuc 
623*433d6423SLionel Sambuc static int
omap_i2c_read(i2c_addr_t addr,uint8_t * buf,size_t buflen,int dostop)624*433d6423SLionel Sambuc omap_i2c_read(i2c_addr_t addr, uint8_t * buf, size_t buflen, int dostop)
625*433d6423SLionel Sambuc {
626*433d6423SLionel Sambuc 	int r, i;
627*433d6423SLionel Sambuc 	uint16_t conopts;
628*433d6423SLionel Sambuc 	uint16_t pollmask;
629*433d6423SLionel Sambuc 	uint16_t errmask;
630*433d6423SLionel Sambuc 
631*433d6423SLionel Sambuc 	/* Set address of slave device */
632*433d6423SLionel Sambuc 	conopts = 0;
633*433d6423SLionel Sambuc 	addr &= MAX_I2C_SA_MASK;	/* sanitize address (10-bit max) */
634*433d6423SLionel Sambuc 	if (addr > 0x7f) {
635*433d6423SLionel Sambuc 		/* 10-bit extended address in use, need to set XSA */
636*433d6423SLionel Sambuc 		conopts |= (1 << XSA);
637*433d6423SLionel Sambuc 	}
638*433d6423SLionel Sambuc 
639*433d6423SLionel Sambuc 	errmask = 0;
640*433d6423SLionel Sambuc 	errmask |= (1 << ROVR);
641*433d6423SLionel Sambuc 	errmask |= (1 << AERR);
642*433d6423SLionel Sambuc 	errmask |= (1 << NACK);
643*433d6423SLionel Sambuc 	errmask |= (1 << AL);
644*433d6423SLionel Sambuc 
645*433d6423SLionel Sambuc 	pollmask = 0;
646*433d6423SLionel Sambuc 	pollmask |= (1 << RRDY);
647*433d6423SLionel Sambuc 
648*433d6423SLionel Sambuc 	/* Set bytes to read and slave address */
649*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CNT, buflen);
650*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SA, addr);
651*433d6423SLionel Sambuc 
652*433d6423SLionel Sambuc 	/* Set control register */
653*433d6423SLionel Sambuc 	conopts |= (1 << I2C_EN);	/* enabled */
654*433d6423SLionel Sambuc 	conopts |= (1 << MST);	/* master mode */
655*433d6423SLionel Sambuc 	conopts |= (1 << STT);	/* start condition */
656*433d6423SLionel Sambuc 
657*433d6423SLionel Sambuc 	if (dostop != 0) {
658*433d6423SLionel Sambuc 		conopts |= (1 << STP);	/* stop condition */
659*433d6423SLionel Sambuc 	}
660*433d6423SLionel Sambuc 
661*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, conopts);
662*433d6423SLionel Sambuc 
663*433d6423SLionel Sambuc 	for (i = 0; i < buflen; i++) {
664*433d6423SLionel Sambuc 		/* Data to read? */
665*433d6423SLionel Sambuc 		r = omap_i2c_poll(pollmask | errmask);
666*433d6423SLionel Sambuc 		if ((r & errmask) != 0) {
667*433d6423SLionel Sambuc 			/* only debug log level because i2cscan trigers this */
668*433d6423SLionel Sambuc 			log_debug(&log, "Read Error! Status=%x\n", r);
669*433d6423SLionel Sambuc 			return EIO;
670*433d6423SLionel Sambuc 		} else if ((r & pollmask) == 0) {
671*433d6423SLionel Sambuc 			log_warn(&log, "No RRDY Interrupt. Status=%x\n", r);
672*433d6423SLionel Sambuc 			log_warn(&log,
673*433d6423SLionel Sambuc 			    "Likely cause: bad pinmux or no devices on bus\n");
674*433d6423SLionel Sambuc 			return EBUSY;
675*433d6423SLionel Sambuc 		}
676*433d6423SLionel Sambuc 
677*433d6423SLionel Sambuc 		/* read a byte */
678*433d6423SLionel Sambuc 		buf[i] = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_DATA) & 0xff;
679*433d6423SLionel Sambuc 
680*433d6423SLionel Sambuc 		/* clear the read ready flag */
681*433d6423SLionel Sambuc 		omap_i2c_write_status(pollmask);
682*433d6423SLionel Sambuc 	}
683*433d6423SLionel Sambuc 
684*433d6423SLionel Sambuc 	r = omap_i2c_read_status();
685*433d6423SLionel Sambuc 	if ((r & (1 << NACK)) != 0) {
686*433d6423SLionel Sambuc 		log_warn(&log, "NACK\n");
687*433d6423SLionel Sambuc 		return EIO;
688*433d6423SLionel Sambuc 	}
689*433d6423SLionel Sambuc 
690*433d6423SLionel Sambuc 	/* Wait for operation to complete */
691*433d6423SLionel Sambuc 	pollmask = (1<<ARDY); /* poll access ready bit */
692*433d6423SLionel Sambuc 	r = omap_i2c_poll(pollmask);
693*433d6423SLionel Sambuc 	if ((r & pollmask) == 0) {
694*433d6423SLionel Sambuc 		log_warn(&log, "Read operation never finished.\n");
695*433d6423SLionel Sambuc 		return EBUSY;
696*433d6423SLionel Sambuc 	}
697*433d6423SLionel Sambuc 	omap_i2c_write_status(0x7fff);
698*433d6423SLionel Sambuc 
699*433d6423SLionel Sambuc 	return 0;
700*433d6423SLionel Sambuc }
701*433d6423SLionel Sambuc 
702*433d6423SLionel Sambuc static int
omap_i2c_write(i2c_addr_t addr,const uint8_t * buf,size_t buflen,int dostop)703*433d6423SLionel Sambuc omap_i2c_write(i2c_addr_t addr, const uint8_t * buf, size_t buflen, int dostop)
704*433d6423SLionel Sambuc {
705*433d6423SLionel Sambuc 	int r, i;
706*433d6423SLionel Sambuc 	uint16_t conopts;
707*433d6423SLionel Sambuc 	uint16_t pollmask;
708*433d6423SLionel Sambuc 	uint16_t errmask;
709*433d6423SLionel Sambuc 
710*433d6423SLionel Sambuc 	/* Set address of slave device */
711*433d6423SLionel Sambuc 	conopts = 0;
712*433d6423SLionel Sambuc 	addr &= MAX_I2C_SA_MASK;	/* sanitize address (10-bit max) */
713*433d6423SLionel Sambuc 	if (addr > 0x7f) {
714*433d6423SLionel Sambuc 		/* 10-bit extended address in use, need to set XSA */
715*433d6423SLionel Sambuc 		conopts |= (1 << XSA);
716*433d6423SLionel Sambuc 	}
717*433d6423SLionel Sambuc 
718*433d6423SLionel Sambuc 	pollmask = 0;
719*433d6423SLionel Sambuc 	pollmask |= (1 << XRDY);
720*433d6423SLionel Sambuc 
721*433d6423SLionel Sambuc 	errmask = 0;
722*433d6423SLionel Sambuc 	errmask |= (1 << ROVR);
723*433d6423SLionel Sambuc 	errmask |= (1 << AERR);
724*433d6423SLionel Sambuc 	errmask |= (1 << NACK);
725*433d6423SLionel Sambuc 	errmask |= (1 << AL);
726*433d6423SLionel Sambuc 
727*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CNT, buflen);
728*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SA, addr);
729*433d6423SLionel Sambuc 
730*433d6423SLionel Sambuc 	/* Set control register */
731*433d6423SLionel Sambuc 	conopts |= (1 << I2C_EN);	/* enabled */
732*433d6423SLionel Sambuc 	conopts |= (1 << MST);	/* master mode */
733*433d6423SLionel Sambuc 	conopts |= (1 << TRX);	/* TRX mode */
734*433d6423SLionel Sambuc 	conopts |= (1 << STT);	/* start condition */
735*433d6423SLionel Sambuc 
736*433d6423SLionel Sambuc 	if (dostop != 0) {
737*433d6423SLionel Sambuc 		conopts |= (1 << STP);	/* stop condition */
738*433d6423SLionel Sambuc 	}
739*433d6423SLionel Sambuc 
740*433d6423SLionel Sambuc 	omap_i2c_write_status(0x7fff);
741*433d6423SLionel Sambuc 	write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, conopts);
742*433d6423SLionel Sambuc 
743*433d6423SLionel Sambuc 	for (i = 0; i < buflen; i++) {
744*433d6423SLionel Sambuc 
745*433d6423SLionel Sambuc 		/* Ready to write? */
746*433d6423SLionel Sambuc 		r = omap_i2c_poll(pollmask | errmask);
747*433d6423SLionel Sambuc 		if ((r & errmask) != 0) {
748*433d6423SLionel Sambuc 			log_warn(&log, "Write Error! Status=%x\n", r);
749*433d6423SLionel Sambuc 			return EIO;
750*433d6423SLionel Sambuc 		} else if ((r & pollmask) == 0) {
751*433d6423SLionel Sambuc 			log_warn(&log, "Not ready for write? Status=%x\n", r);
752*433d6423SLionel Sambuc 			return EBUSY;
753*433d6423SLionel Sambuc 		}
754*433d6423SLionel Sambuc 
755*433d6423SLionel Sambuc 		write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_DATA, buf[i]);
756*433d6423SLionel Sambuc 
757*433d6423SLionel Sambuc 		/* clear the write ready flag */
758*433d6423SLionel Sambuc 		omap_i2c_write_status(pollmask);
759*433d6423SLionel Sambuc 	}
760*433d6423SLionel Sambuc 
761*433d6423SLionel Sambuc 	r = omap_i2c_read_status();
762*433d6423SLionel Sambuc 	if ((r & (1 << NACK)) != 0) {
763*433d6423SLionel Sambuc 		log_warn(&log, "NACK\n");
764*433d6423SLionel Sambuc 		return EIO;
765*433d6423SLionel Sambuc 	}
766*433d6423SLionel Sambuc 
767*433d6423SLionel Sambuc 	/* Wait for operation to complete */
768*433d6423SLionel Sambuc 	pollmask = (1<<ARDY); /* poll access ready bit */
769*433d6423SLionel Sambuc 	r = omap_i2c_poll(pollmask);
770*433d6423SLionel Sambuc 	if ((r & pollmask) == 0) {
771*433d6423SLionel Sambuc 		log_warn(&log, "Write operation never finished.\n");
772*433d6423SLionel Sambuc 		return EBUSY;
773*433d6423SLionel Sambuc 	}
774*433d6423SLionel Sambuc 	omap_i2c_write_status(0x7fff);
775*433d6423SLionel Sambuc 
776*433d6423SLionel Sambuc 	return 0;
777*433d6423SLionel Sambuc }
778*433d6423SLionel Sambuc 
779*433d6423SLionel Sambuc int
omap_interface_setup(int (** process)(minix_i2c_ioctl_exec_t * ioctl_exec),int i2c_bus_id)780*433d6423SLionel Sambuc omap_interface_setup(int (**process) (minix_i2c_ioctl_exec_t * ioctl_exec),
781*433d6423SLionel Sambuc     int i2c_bus_id)
782*433d6423SLionel Sambuc {
783*433d6423SLionel Sambuc 	int r;
784*433d6423SLionel Sambuc 	int i2c_rev, major, minor;
785*433d6423SLionel Sambuc 	struct minix_mem_range mr;
786*433d6423SLionel Sambuc 	struct machine machine;
787*433d6423SLionel Sambuc 	sys_getmachine(&machine);
788*433d6423SLionel Sambuc 
789*433d6423SLionel Sambuc 	/* Fill in the function pointer */
790*433d6423SLionel Sambuc 
791*433d6423SLionel Sambuc 	*process = omap_i2c_process;
792*433d6423SLionel Sambuc 
793*433d6423SLionel Sambuc 	/* Select the correct i2c definition for this SoC */
794*433d6423SLionel Sambuc 
795*433d6423SLionel Sambuc 	if (BOARD_IS_BBXM(machine.board_id)){
796*433d6423SLionel Sambuc 		omap_i2c_buses = dm37xx_i2c_buses;
797*433d6423SLionel Sambuc 		omap_i2c_nbuses = DM37XX_OMAP_NBUSES;
798*433d6423SLionel Sambuc 	} else if (BOARD_IS_BB(machine.board_id)){
799*433d6423SLionel Sambuc 		omap_i2c_buses = am335x_i2c_buses;
800*433d6423SLionel Sambuc 		omap_i2c_nbuses = AM335X_OMAP_NBUSES;
801*433d6423SLionel Sambuc 	} else {
802*433d6423SLionel Sambuc 		return EINVAL;
803*433d6423SLionel Sambuc 	}
804*433d6423SLionel Sambuc 
805*433d6423SLionel Sambuc 	if (i2c_bus_id < 0 || i2c_bus_id >= omap_i2c_nbuses) {
806*433d6423SLionel Sambuc 		return EINVAL;
807*433d6423SLionel Sambuc 	}
808*433d6423SLionel Sambuc 
809*433d6423SLionel Sambuc 	/* select the bus to operate on */
810*433d6423SLionel Sambuc 	omap_i2c_bus = &omap_i2c_buses[i2c_bus_id];
811*433d6423SLionel Sambuc 
812*433d6423SLionel Sambuc 	/* Configure Pins */
813*433d6423SLionel Sambuc 	omap_i2c_padconf(i2c_bus_id);
814*433d6423SLionel Sambuc 
815*433d6423SLionel Sambuc 	/*
816*433d6423SLionel Sambuc 	 * Map I2C Registers
817*433d6423SLionel Sambuc 	 */
818*433d6423SLionel Sambuc 
819*433d6423SLionel Sambuc 	/* Configure memory access */
820*433d6423SLionel Sambuc 	mr.mr_base = omap_i2c_bus->mr_base;	/* start addr */
821*433d6423SLionel Sambuc 	mr.mr_limit = mr.mr_base + omap_i2c_bus->mr_size;	/* end addr */
822*433d6423SLionel Sambuc 
823*433d6423SLionel Sambuc 	/* ask for privileges to access the I2C memory range */
824*433d6423SLionel Sambuc 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
825*433d6423SLionel Sambuc 		panic("Unable to obtain i2c memory range privileges");
826*433d6423SLionel Sambuc 	}
827*433d6423SLionel Sambuc 
828*433d6423SLionel Sambuc 	/* map the memory into this process */
829*433d6423SLionel Sambuc 	omap_i2c_bus->mapped_addr = (vir_bytes) vm_map_phys(SELF,
830*433d6423SLionel Sambuc 	    (void *) omap_i2c_bus->mr_base, omap_i2c_bus->mr_size);
831*433d6423SLionel Sambuc 
832*433d6423SLionel Sambuc 	if (omap_i2c_bus->mapped_addr == (vir_bytes) MAP_FAILED) {
833*433d6423SLionel Sambuc 		panic("Unable to map i2c registers");
834*433d6423SLionel Sambuc 	}
835*433d6423SLionel Sambuc 
836*433d6423SLionel Sambuc 	/* Enable Clocks */
837*433d6423SLionel Sambuc 	omap_i2c_clkconf(i2c_bus_id);
838*433d6423SLionel Sambuc 
839*433d6423SLionel Sambuc 	/* Perform a soft reset of the I2C module to ensure a fresh start */
840*433d6423SLionel Sambuc 	r = omap_i2c_soft_reset();
841*433d6423SLionel Sambuc 	if (r != OK) {
842*433d6423SLionel Sambuc 		/* module didn't come back up :( */
843*433d6423SLionel Sambuc 		return r;
844*433d6423SLionel Sambuc 	}
845*433d6423SLionel Sambuc 
846*433d6423SLionel Sambuc 	/* Bring up I2C module */
847*433d6423SLionel Sambuc 	omap_i2c_bus_init();
848*433d6423SLionel Sambuc 
849*433d6423SLionel Sambuc 	/* Get I2C Revision */
850*433d6423SLionel Sambuc 	if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
851*433d6423SLionel Sambuc 		/* I2C_REVLO revision: major (bits 10-8), minor (bits 5-0) */
852*433d6423SLionel Sambuc 		i2c_rev = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_REVNB_LO);
853*433d6423SLionel Sambuc 		major = (i2c_rev >> 8) & 0x07;
854*433d6423SLionel Sambuc 		minor = i2c_rev & 0x3f;
855*433d6423SLionel Sambuc 
856*433d6423SLionel Sambuc 	} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
857*433d6423SLionel Sambuc 		/* I2C_REV revision: major (bits 7-4), minor (bits 3-0) */
858*433d6423SLionel Sambuc 		i2c_rev = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_REV);
859*433d6423SLionel Sambuc 		major = (i2c_rev >> 4) & 0x0f;
860*433d6423SLionel Sambuc 		minor = i2c_rev & 0x0f;
861*433d6423SLionel Sambuc 	} else {
862*433d6423SLionel Sambuc 		panic("Don't know how to read i2c revision.");
863*433d6423SLionel Sambuc 	}
864*433d6423SLionel Sambuc 
865*433d6423SLionel Sambuc 	if (major != omap_i2c_bus->major || minor != omap_i2c_bus->minor) {
866*433d6423SLionel Sambuc 		log_warn(&log, "Unrecognized value in I2C_REV register.\n");
867*433d6423SLionel Sambuc 		log_warn(&log, "Read: 0x%x.0x%x | Expected: 0x%x.0x%x\n",
868*433d6423SLionel Sambuc 		    major, minor, omap_i2c_bus->major, omap_i2c_bus->minor);
869*433d6423SLionel Sambuc 	}
870*433d6423SLionel Sambuc 
871*433d6423SLionel Sambuc 	/* display i2c revision information for debugging purposes */
872*433d6423SLionel Sambuc 	log_debug(&log, "i2c_%d: I2C rev 0x%x.0x%x\n", (i2c_bus_id + 1),
873*433d6423SLionel Sambuc 	    major, minor);
874*433d6423SLionel Sambuc 
875*433d6423SLionel Sambuc 	return OK;
876*433d6423SLionel Sambuc }
877