blob: f780721e1039696ec7742f358a10a739d873538e [file] [log] [blame]
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -05001/*
2 * Setup helpers for Two Wire Interface (TWI) (I²C) Allwinner CPUs
3 *
4 * Only functionality for I²C master is provided.
5 * Largely based on the uboot-sunxi code.
6 *
7 * Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
8 * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
9 * Subject to the GNU GPL v2, or (at your option) any later version.
10 */
11
12#include "memmap.h"
13#include "twi.h"
14
15#include <arch/io.h>
16#include <delay.h>
17#include <device/i2c.h>
18
19#define TWI_BASE(n) (A1X_TWI0_BASE + 0x400 * (n))
20
21#define TWI_TIMEOUT (50 * 1000)
22
23static u8 is_busy(struct a1x_twi *twi)
24{
25 return (read32(&twi->stat) != TWI_STAT_IDLE);
26}
27
28static enum cb_err wait_until_idle(struct a1x_twi *twi)
29{
30 u32 i = TWI_TIMEOUT;
31 while (i-- && is_busy((twi)))
32 udelay(1);
33 return i ? CB_SUCCESS : CB_ERR;
34}
35
36/* FIXME: This function is basic, and unintelligent */
37static void configure_clock(struct a1x_twi *twi, u32 speed_hz)
38{
39 /* FIXME: We assume clock is 24MHz, which may not be the case */
40 u32 apb_clk = 24000000, m, n;
41
42 /* Pre-divide the clock by 8 */
43 n = 3;
44 m = (apb_clk >> n) / speed_hz;
Julius Werner2f37bd62015-02-19 14:51:15 -080045 write32(&twi->clk, TWI_CLK_M(m) | TWI_CLK_N(n));
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -050046}
47
48void a1x_twi_init(u8 bus, u32 speed_hz)
49{
50 u32 i = TWI_TIMEOUT;
51 struct a1x_twi *twi = (void *)TWI_BASE(bus);
52
53 configure_clock(twi, speed_hz);
54
55 /* Enable the I²C bus */
Julius Werner2f37bd62015-02-19 14:51:15 -080056 write32(&twi->ctl, TWI_CTL_BUS_EN);
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -050057 /* Issue soft reset */
Julius Werner2f37bd62015-02-19 14:51:15 -080058 write32(&twi->reset, 1);
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -050059
60 while (i-- && read32(&twi->reset))
61 udelay(1);
62}
63
64static void clear_interrupt_flag(struct a1x_twi *twi)
65{
Julius Werner2f37bd62015-02-19 14:51:15 -080066 write32(&twi->ctl, read32(&twi->ctl) & ~TWI_CTL_INT_FLAG);
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -050067}
68
69static void i2c_send_data(struct a1x_twi *twi, u8 data)
70{
Julius Werner2f37bd62015-02-19 14:51:15 -080071 write32(&twi->data, data);
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -050072 clear_interrupt_flag(twi);
73}
74
75static enum twi_status wait_for_status(struct a1x_twi *twi)
76{
77 u32 i = TWI_TIMEOUT;
78 /* Wait until interrupt is asserted again */
79 while (i-- && !(read32(&twi->ctl) & TWI_CTL_INT_FLAG))
80 udelay(1);
81 /* A timeout here most likely indicates a bus error */
82 return i ? read32(&twi->stat) : TWI_STAT_BUS_ERROR;
83}
84
85static void i2c_send_start(struct a1x_twi *twi)
86{
87 u32 reg32, i;
88
89 /* Send START condition */
90 reg32 = read32(&twi->ctl);
91 reg32 &= ~TWI_CTL_INT_FLAG;
92 reg32 |= TWI_CTL_M_START;
Julius Werner2f37bd62015-02-19 14:51:15 -080093 write32(&twi->ctl, reg32);
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -050094
95 /* M_START is automatically cleared after condition is transmitted */
96 i = TWI_TIMEOUT;
97 while (i-- && (read32(&twi->ctl) & TWI_CTL_M_START))
98 udelay(1);
99}
100
101static void i2c_send_stop(struct a1x_twi *twi)
102{
103 u32 reg32;
104
105 /* Send STOP condition */
106 reg32 = read32(&twi->ctl);
107 reg32 &= ~TWI_CTL_INT_FLAG;
108 reg32 |= TWI_CTL_M_STOP;
Julius Werner2f37bd62015-02-19 14:51:15 -0800109 write32(&twi->ctl, reg32);
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500110}
111
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600112static int i2c_read(struct a1x_twi *twi, uint8_t chip,
113 uint8_t *buf, size_t len)
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500114{
115 unsigned count = len;
116 enum twi_status expected_status;
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500117
118 /* Send restart for read */
119 i2c_send_start(twi);
120 if (wait_for_status(twi) != TWI_STAT_TX_RSTART)
121 return CB_ERR;
122
123 /* Send chip address */
124 i2c_send_data(twi, chip << 1 | 1);
125 if (wait_for_status(twi) != TWI_STAT_TX_AR_ACK)
126 return CB_ERR;
127
128 /* Start ACK-ing received data */
129 setbits_le32(&twi->ctl, TWI_CTL_A_ACK);
130 expected_status = TWI_STAT_RXD_ACK;
131
132 /* Read data */
133 while (count > 0) {
134 if (count == 1) {
135 /* Do not ACK the last byte */
136 clrbits_le32(&twi->ctl, TWI_CTL_A_ACK);
137 expected_status = TWI_STAT_RXD_NAK;
138 }
139
140 clear_interrupt_flag(twi);
141
142 if (wait_for_status(twi) != expected_status)
143 return CB_ERR;
144
145 *buf++ = read32(&twi->data);
146 count--;
147 }
148
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500149 return len;
150}
151
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600152static int i2c_write(struct a1x_twi *twi, uint8_t chip,
153 const uint8_t *buf, size_t len)
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500154{
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600155 size_t count = len;
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500156
157 i2c_send_start(twi);
158 if (wait_for_status(twi) != TWI_STAT_TX_START)
159 return CB_ERR;
160
161 /* Send chip address */
162 i2c_send_data(twi, chip << 1);
163 if (wait_for_status(twi) != TWI_STAT_TX_AW_ACK)
164 return CB_ERR;
165
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500166 /* Send data */
167 while (count > 0) {
168 i2c_send_data(twi, *buf++);
169 if (wait_for_status(twi) != TWI_STAT_TXD_ACK)
170 return CB_ERR;
171 count--;
172 }
173
Alexandru Gagniuc5c4bde72013-12-28 21:50:54 -0500174 return len;
175}
Gabe Blackcdb61a62014-04-07 18:45:14 -0700176
Julius Werner37d7ac82014-05-05 18:03:46 -0700177int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int count)
Gabe Blackcdb61a62014-04-07 18:45:14 -0700178{
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600179 int i, ret = CB_SUCCESS;
Gabe Blackcdb61a62014-04-07 18:45:14 -0700180 struct i2c_seg *seg = segments;
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600181 struct a1x_twi *twi = (void *)TWI_BASE(bus);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700182
Gabe Blackcdb61a62014-04-07 18:45:14 -0700183
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600184 if (wait_until_idle(twi) != CB_SUCCESS)
185 return CB_ERR;
Gabe Blackcdb61a62014-04-07 18:45:14 -0700186
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600187 for (i = 0; i < count; i++) {
188 seg = segments + i;
189
190 if (seg->read) {
191 ret = i2c_read(twi, seg->chip, seg->buf, seg->len);
192 if (ret < 0)
193 break;
194 } else {
195 ret = i2c_write(twi, seg->chip, seg->buf, seg->len);
196 if (ret < 0)
197 break;
198 }
Gabe Blackcdb61a62014-04-07 18:45:14 -0700199 }
Alexandru Gagniuce5ccbfd2015-02-13 16:30:30 -0600200
201 /* Don't worry about the status. STOP is on a best-effort basis */
202 i2c_send_stop(twi);
203
204 return ret;
Gabe Blackcdb61a62014-04-07 18:45:14 -0700205}