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