meson_i2c.c revision 1.2.4.2 1 1.2.4.2 perseant /* $NetBSD: meson_i2c.c,v 1.2.4.2 2025/08/02 05:55:26 perseant Exp $ */
2 1.2.4.2 perseant
3 1.2.4.2 perseant /*-
4 1.2.4.2 perseant * Copyright (c) 2025 The NetBSD Foundation, Inc.
5 1.2.4.2 perseant * All rights reserved.
6 1.2.4.2 perseant *
7 1.2.4.2 perseant * Written by Vincent Defert for The NetBSD Foundation, Inc.
8 1.2.4.2 perseant *
9 1.2.4.2 perseant * Redistribution and use in source and binary forms, with or without
10 1.2.4.2 perseant * modification, are permitted provided that the following conditions
11 1.2.4.2 perseant * are met:
12 1.2.4.2 perseant * 1. Redistributions of source code must retain the above copyright
13 1.2.4.2 perseant * notice, this list of conditions and the following disclaimer.
14 1.2.4.2 perseant * 2. Redistributions in binary form must reproduce the above copyright
15 1.2.4.2 perseant * notice, this list of conditions and the following disclaimer in the
16 1.2.4.2 perseant * documentation and/or other materials provided with the distribution.
17 1.2.4.2 perseant *
18 1.2.4.2 perseant * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 1.2.4.2 perseant * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 1.2.4.2 perseant * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 1.2.4.2 perseant * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 1.2.4.2 perseant * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 1.2.4.2 perseant * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 1.2.4.2 perseant * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 1.2.4.2 perseant * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 1.2.4.2 perseant * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 1.2.4.2 perseant * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.2.4.2 perseant * POSSIBILITY OF SUCH DAMAGE.
29 1.2.4.2 perseant */
30 1.2.4.2 perseant
31 1.2.4.2 perseant #include <sys/cdefs.h>
32 1.2.4.2 perseant __KERNEL_RCSID(1, "$NetBSD: meson_i2c.c,v 1.2.4.2 2025/08/02 05:55:26 perseant Exp $");
33 1.2.4.2 perseant
34 1.2.4.2 perseant #include <sys/param.h>
35 1.2.4.2 perseant #include <sys/bus.h>
36 1.2.4.2 perseant #include <sys/device.h>
37 1.2.4.2 perseant #include <sys/intr.h>
38 1.2.4.2 perseant #include <sys/systm.h>
39 1.2.4.2 perseant #include <sys/time.h>
40 1.2.4.2 perseant #include <sys/kmem.h>
41 1.2.4.2 perseant #include <sys/mutex.h>
42 1.2.4.2 perseant #include <sys/condvar.h>
43 1.2.4.2 perseant #include <dev/i2c/i2cvar.h>
44 1.2.4.2 perseant #include <dev/fdt/fdtvar.h>
45 1.2.4.2 perseant
46 1.2.4.2 perseant #define MESONI2C_CTRL_REG 0x00
47 1.2.4.2 perseant #define MESONI2C_CTRL_START __BIT(0)
48 1.2.4.2 perseant #define MESONI2C_CTRL_ACK_IGNORE __BIT(1)
49 1.2.4.2 perseant #define MESONI2C_CTRL_STATUS __BIT(2)
50 1.2.4.2 perseant #define MESONI2C_CTRL_ERROR __BIT(3)
51 1.2.4.2 perseant #define MESONI2C_CTRL_READ_DATA_SHIFT 8
52 1.2.4.2 perseant #define MESONI2C_CTRL_READ_DATA_MASK __BITS(11, MESONI2C_CTRL_READ_DATA_SHIFT)
53 1.2.4.2 perseant #define MESONI2C_CTRL_CLKDIV_SHIFT 12
54 1.2.4.2 perseant #define MESONI2C_CTRL_CLKDIV_MASK __BITS(21, MESONI2C_CTRL_CLKDIV_SHIFT)
55 1.2.4.2 perseant #define MESONI2C_CTRL_CLKDIVEXT_SHIFT 28
56 1.2.4.2 perseant #define MESONI2C_CTRL_CLKDIVEXT_MASK __BITS(29, MESONI2C_CTRL_CLKDIVEXT_SHIFT)
57 1.2.4.2 perseant
58 1.2.4.2 perseant #define MESONI2C_SLAVE_ADDR_REG 0x04
59 1.2.4.2 perseant #define MESONI2C_SLAVE_ADDR_MASK __BITS(7, 0)
60 1.2.4.2 perseant #define MESONI2C_SLAVE_SDA_FILTER_MASK __BITS(10, 8)
61 1.2.4.2 perseant #define MESONI2C_SLAVE_SCL_FILTER_MASK __BITS(13, 11)
62 1.2.4.2 perseant #define MESONI2C_SLAVE_SCL_LOW_SHIFT 16
63 1.2.4.2 perseant #define MESONI2C_SLAVE_SCL_LOW_MASK __BITS(27, MESONI2C_SLAVE_SCL_LOW_SHIFT)
64 1.2.4.2 perseant #define MESONI2C_SLAVE_SCL_LOW_EN __BIT(28)
65 1.2.4.2 perseant
66 1.2.4.2 perseant #define MESONI2C_TOKEN_LIST_REG0 0x08
67 1.2.4.2 perseant #define MESONI2C_TOKEN_LIST_REG1 0x0c
68 1.2.4.2 perseant #define MESONI2C_TOKEN_WDATA_REG0 0x10
69 1.2.4.2 perseant #define MESONI2C_TOKEN_WDATA_REG1 0x14
70 1.2.4.2 perseant #define MESONI2C_TOKEN_RDATA_REG0 0x18
71 1.2.4.2 perseant #define MESONI2C_TOKEN_RDATA_REG1 0x1c
72 1.2.4.2 perseant
73 1.2.4.2 perseant #define MESONI2C_TOKEN_BITS 4
74 1.2.4.2 perseant #define MESONI2C_TOKEN_MASK ((1 << MESONI2C_TOKEN_BITS) - 1)
75 1.2.4.2 perseant #define MESONI2C_TOKEN_REG_HALF (32 / MESONI2C_TOKEN_BITS)
76 1.2.4.2 perseant #define MESONI2C_TOKEN_REG_FULL (64 / MESONI2C_TOKEN_BITS)
77 1.2.4.2 perseant
78 1.2.4.2 perseant #define MESONI2C_DATA_BITS 8
79 1.2.4.2 perseant #define MESONI2C_DATA_MASK ((1 << MESONI2C_DATA_BITS) - 1)
80 1.2.4.2 perseant #define MESONI2C_DATA_REG_HALF (32 / MESONI2C_DATA_BITS)
81 1.2.4.2 perseant #define MESONI2C_DATA_REG_FULL (64 / MESONI2C_DATA_BITS)
82 1.2.4.2 perseant
83 1.2.4.2 perseant #define I2C_TIMEOUT_MS 1000
84 1.2.4.2 perseant #define FILTER_DELAY 15
85 1.2.4.2 perseant
86 1.2.4.2 perseant enum mesoni2c_token {
87 1.2.4.2 perseant TOKEN_END = 0,
88 1.2.4.2 perseant TOKEN_START,
89 1.2.4.2 perseant TOKEN_SLAVE_ADDR_WRITE,
90 1.2.4.2 perseant TOKEN_SLAVE_ADDR_READ,
91 1.2.4.2 perseant TOKEN_DATA,
92 1.2.4.2 perseant TOKEN_DATA_LAST,
93 1.2.4.2 perseant TOKEN_STOP,
94 1.2.4.2 perseant };
95 1.2.4.2 perseant
96 1.2.4.2 perseant enum mesoni2c_type {
97 1.2.4.2 perseant TYPE_MESON6,
98 1.2.4.2 perseant TYPE_GXBB,
99 1.2.4.2 perseant TYPE_AXG,
100 1.2.4.2 perseant };
101 1.2.4.2 perseant
102 1.2.4.2 perseant struct mesoni2c_softc {
103 1.2.4.2 perseant device_t sc_dev;
104 1.2.4.2 perseant bus_space_tag_t sc_bst;
105 1.2.4.2 perseant bus_space_handle_t sc_bsh;
106 1.2.4.2 perseant struct clk *sc_clk;
107 1.2.4.2 perseant u_int sc_clkfreq;
108 1.2.4.2 perseant struct i2c_controller sc_ic;
109 1.2.4.2 perseant kcondvar_t sc_cv;
110 1.2.4.2 perseant kmutex_t sc_mtx;
111 1.2.4.2 perseant void *sc_ih;
112 1.2.4.2 perseant
113 1.2.4.2 perseant u_int sc_token_index;
114 1.2.4.2 perseant u_int sc_wdata_index;
115 1.2.4.2 perseant u_int sc_rdata_index;
116 1.2.4.2 perseant
117 1.2.4.2 perseant const uint8_t *sc_cmdbuf;
118 1.2.4.2 perseant size_t sc_cmdlen;
119 1.2.4.2 perseant uint8_t *sc_databuf;
120 1.2.4.2 perseant size_t sc_datalen;
121 1.2.4.2 perseant i2c_op_t sc_op;
122 1.2.4.2 perseant
123 1.2.4.2 perseant size_t sc_curlen;
124 1.2.4.2 perseant i2c_op_t sc_curop;
125 1.2.4.2 perseant int sc_sendingCmd;
126 1.2.4.2 perseant int sc_error;
127 1.2.4.2 perseant };
128 1.2.4.2 perseant
129 1.2.4.2 perseant static void mesoni2c_set_mask(struct mesoni2c_softc *sc, bus_size_t reg, uint32_t mask, uint32_t value);
130 1.2.4.2 perseant static void mesoni2c_reset_state(struct mesoni2c_softc *sc);
131 1.2.4.2 perseant static int mesoni2c_push_token(struct mesoni2c_softc *sc, enum mesoni2c_token token);
132 1.2.4.2 perseant static void mesoni2c_write_byte(struct mesoni2c_softc *sc, uint8_t data);
133 1.2.4.2 perseant static uint8_t mesoni2c_get_byte(struct mesoni2c_softc *sc);
134 1.2.4.2 perseant static void mesoni2c_prepare_xfer(struct mesoni2c_softc *sc, i2c_op_t op);
135 1.2.4.2 perseant static void mesoni2c_partial_xfer(struct mesoni2c_softc *sc);
136 1.2.4.2 perseant static int mesoni2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t buflen, int flags);
137 1.2.4.2 perseant static int mesoni2c_intr(void *arg);
138 1.2.4.2 perseant static void mesoni2c_set_clock_div_meson6(struct mesoni2c_softc *sc);
139 1.2.4.2 perseant static void mesoni2c_set_clock_div_gxbb_axg(struct mesoni2c_softc *sc);
140 1.2.4.2 perseant static int mesoni2c_match(device_t parent, cfdata_t cf, void *aux);
141 1.2.4.2 perseant static void mesoni2c_attach(device_t parent, device_t self, void *aux);
142 1.2.4.2 perseant
143 1.2.4.2 perseant CFATTACH_DECL_NEW(meson_i2c, sizeof(struct mesoni2c_softc),
144 1.2.4.2 perseant mesoni2c_match, mesoni2c_attach, NULL, NULL);
145 1.2.4.2 perseant
146 1.2.4.2 perseant static const struct device_compatible_entry compat_data[] = {
147 1.2.4.2 perseant { .compat = "amlogic,meson6-i2c", .value = TYPE_MESON6 },
148 1.2.4.2 perseant { .compat = "amlogic,meson-gxbb-i2c", .value = TYPE_GXBB },
149 1.2.4.2 perseant { .compat = "amlogic,meson-axg-i2c", .value = TYPE_AXG },
150 1.2.4.2 perseant DEVICE_COMPAT_EOL
151 1.2.4.2 perseant };
152 1.2.4.2 perseant
153 1.2.4.2 perseant #define RD4(sc, reg) \
154 1.2.4.2 perseant bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
155 1.2.4.2 perseant
156 1.2.4.2 perseant #define WR4(sc, reg, val) \
157 1.2.4.2 perseant bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
158 1.2.4.2 perseant
159 1.2.4.2 perseant static void
160 1.2.4.2 perseant mesoni2c_set_mask(struct mesoni2c_softc *sc, bus_size_t reg, uint32_t mask,
161 1.2.4.2 perseant uint32_t value)
162 1.2.4.2 perseant {
163 1.2.4.2 perseant uint32_t data = RD4(sc, reg);
164 1.2.4.2 perseant data &= ~mask;
165 1.2.4.2 perseant data |= value & mask;
166 1.2.4.2 perseant WR4(sc, reg, data);
167 1.2.4.2 perseant }
168 1.2.4.2 perseant
169 1.2.4.2 perseant static void
170 1.2.4.2 perseant mesoni2c_reset_state(struct mesoni2c_softc *sc)
171 1.2.4.2 perseant {
172 1.2.4.2 perseant sc->sc_token_index = 0;
173 1.2.4.2 perseant sc->sc_wdata_index = 0;
174 1.2.4.2 perseant sc->sc_rdata_index = 0;
175 1.2.4.2 perseant }
176 1.2.4.2 perseant
177 1.2.4.2 perseant static int
178 1.2.4.2 perseant mesoni2c_push_token(struct mesoni2c_softc *sc, enum mesoni2c_token token)
179 1.2.4.2 perseant {
180 1.2.4.2 perseant bus_size_t reg;
181 1.2.4.2 perseant u_int pos;
182 1.2.4.2 perseant
183 1.2.4.2 perseant if (sc->sc_token_index >= MESONI2C_TOKEN_REG_HALF) {
184 1.2.4.2 perseant reg = MESONI2C_TOKEN_LIST_REG1;
185 1.2.4.2 perseant pos = sc->sc_token_index - MESONI2C_TOKEN_REG_HALF;
186 1.2.4.2 perseant } else {
187 1.2.4.2 perseant reg = MESONI2C_TOKEN_LIST_REG0;
188 1.2.4.2 perseant pos = sc->sc_token_index;
189 1.2.4.2 perseant }
190 1.2.4.2 perseant
191 1.2.4.2 perseant sc->sc_token_index++;
192 1.2.4.2 perseant pos *= MESONI2C_TOKEN_BITS;
193 1.2.4.2 perseant mesoni2c_set_mask(sc, reg, MESONI2C_TOKEN_MASK << pos, token << pos);
194 1.2.4.2 perseant
195 1.2.4.2 perseant return sc->sc_token_index == MESONI2C_TOKEN_REG_FULL;
196 1.2.4.2 perseant }
197 1.2.4.2 perseant
198 1.2.4.2 perseant static void
199 1.2.4.2 perseant mesoni2c_write_byte(struct mesoni2c_softc *sc, uint8_t data)
200 1.2.4.2 perseant {
201 1.2.4.2 perseant bus_size_t reg;
202 1.2.4.2 perseant u_int pos;
203 1.2.4.2 perseant
204 1.2.4.2 perseant if (sc->sc_wdata_index >= MESONI2C_DATA_REG_HALF) {
205 1.2.4.2 perseant reg = MESONI2C_TOKEN_WDATA_REG1;
206 1.2.4.2 perseant pos = sc->sc_wdata_index - MESONI2C_DATA_REG_HALF;
207 1.2.4.2 perseant } else {
208 1.2.4.2 perseant reg = MESONI2C_TOKEN_WDATA_REG0;
209 1.2.4.2 perseant pos = sc->sc_wdata_index;
210 1.2.4.2 perseant }
211 1.2.4.2 perseant
212 1.2.4.2 perseant sc->sc_wdata_index++;
213 1.2.4.2 perseant pos *= MESONI2C_DATA_BITS;
214 1.2.4.2 perseant mesoni2c_set_mask(sc, reg, MESONI2C_DATA_MASK << pos, ((uint32_t) data) << pos);
215 1.2.4.2 perseant mesoni2c_push_token(sc, TOKEN_DATA);
216 1.2.4.2 perseant }
217 1.2.4.2 perseant
218 1.2.4.2 perseant static uint8_t
219 1.2.4.2 perseant mesoni2c_get_byte(struct mesoni2c_softc *sc)
220 1.2.4.2 perseant {
221 1.2.4.2 perseant bus_size_t reg;
222 1.2.4.2 perseant u_int pos;
223 1.2.4.2 perseant
224 1.2.4.2 perseant if (sc->sc_rdata_index >= MESONI2C_DATA_REG_HALF) {
225 1.2.4.2 perseant reg = MESONI2C_TOKEN_RDATA_REG1;
226 1.2.4.2 perseant pos = sc->sc_rdata_index - MESONI2C_DATA_REG_HALF;
227 1.2.4.2 perseant } else {
228 1.2.4.2 perseant reg = MESONI2C_TOKEN_RDATA_REG0;
229 1.2.4.2 perseant pos = sc->sc_rdata_index;
230 1.2.4.2 perseant }
231 1.2.4.2 perseant
232 1.2.4.2 perseant sc->sc_rdata_index++;
233 1.2.4.2 perseant pos *= MESONI2C_DATA_BITS;
234 1.2.4.2 perseant
235 1.2.4.2 perseant return (RD4(sc, reg) >> pos) & MESONI2C_DATA_MASK;
236 1.2.4.2 perseant }
237 1.2.4.2 perseant
238 1.2.4.2 perseant static void
239 1.2.4.2 perseant mesoni2c_prepare_xfer(struct mesoni2c_softc *sc, i2c_op_t op)
240 1.2.4.2 perseant {
241 1.2.4.2 perseant mesoni2c_reset_state(sc);
242 1.2.4.2 perseant mesoni2c_push_token(sc, TOKEN_START);
243 1.2.4.2 perseant mesoni2c_push_token(sc, I2C_OP_WRITE_P(op) ? TOKEN_SLAVE_ADDR_WRITE : TOKEN_SLAVE_ADDR_READ);
244 1.2.4.2 perseant }
245 1.2.4.2 perseant
246 1.2.4.2 perseant static void
247 1.2.4.2 perseant mesoni2c_partial_xfer(struct mesoni2c_softc *sc)
248 1.2.4.2 perseant {
249 1.2.4.2 perseant int dataBufferFree = MESONI2C_DATA_REG_FULL;
250 1.2.4.2 perseant
251 1.2.4.2 perseant while (sc->sc_curlen && dataBufferFree) {
252 1.2.4.2 perseant sc->sc_curlen--;
253 1.2.4.2 perseant dataBufferFree--;
254 1.2.4.2 perseant
255 1.2.4.2 perseant if (I2C_OP_WRITE_P(sc->sc_curop)) {
256 1.2.4.2 perseant if (sc->sc_sendingCmd) {
257 1.2.4.2 perseant uint8_t c = *(sc->sc_cmdbuf++);
258 1.2.4.2 perseant mesoni2c_write_byte(sc, c);
259 1.2.4.2 perseant } else {
260 1.2.4.2 perseant mesoni2c_write_byte(sc, *(sc->sc_databuf++));
261 1.2.4.2 perseant }
262 1.2.4.2 perseant } else {
263 1.2.4.2 perseant mesoni2c_push_token(sc, sc->sc_curlen ? TOKEN_DATA : TOKEN_DATA_LAST);
264 1.2.4.2 perseant }
265 1.2.4.2 perseant }
266 1.2.4.2 perseant
267 1.2.4.2 perseant if (sc->sc_curlen == 0 && I2C_OP_STOP_P(sc->sc_curop)) {
268 1.2.4.2 perseant mesoni2c_push_token(sc, TOKEN_STOP);
269 1.2.4.2 perseant }
270 1.2.4.2 perseant
271 1.2.4.2 perseant mesoni2c_push_token(sc, TOKEN_END);
272 1.2.4.2 perseant
273 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_START, 0);
274 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_START, 1);
275 1.2.4.2 perseant }
276 1.2.4.2 perseant
277 1.2.4.2 perseant static int
278 1.2.4.2 perseant mesoni2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
279 1.2.4.2 perseant size_t cmdlen, void *databuf, size_t datalen, int flags)
280 1.2.4.2 perseant {
281 1.2.4.2 perseant struct mesoni2c_softc * const sc = priv;
282 1.2.4.2 perseant
283 1.2.4.2 perseant mutex_enter(&sc->sc_mtx);
284 1.2.4.2 perseant
285 1.2.4.2 perseant sc->sc_cmdbuf = cmdbuf;
286 1.2.4.2 perseant sc->sc_cmdlen = cmdlen;
287 1.2.4.2 perseant sc->sc_databuf = databuf;
288 1.2.4.2 perseant sc->sc_datalen = datalen;
289 1.2.4.2 perseant sc->sc_op = op;
290 1.2.4.2 perseant sc->sc_error = 0;
291 1.2.4.2 perseant
292 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_ADDR_MASK, addr << 1);
293 1.2.4.2 perseant
294 1.2.4.2 perseant if (cmdlen) {
295 1.2.4.2 perseant sc->sc_curlen = cmdlen;
296 1.2.4.2 perseant sc->sc_curop = datalen ? I2C_OP_WRITE : op;
297 1.2.4.2 perseant sc->sc_sendingCmd = 1;
298 1.2.4.2 perseant } else {
299 1.2.4.2 perseant sc->sc_curlen = datalen;
300 1.2.4.2 perseant sc->sc_curop = op;
301 1.2.4.2 perseant sc->sc_sendingCmd = 0;
302 1.2.4.2 perseant }
303 1.2.4.2 perseant
304 1.2.4.2 perseant mesoni2c_prepare_xfer(sc, sc->sc_curop);
305 1.2.4.2 perseant mesoni2c_partial_xfer(sc);
306 1.2.4.2 perseant
307 1.2.4.2 perseant if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, mstohz(I2C_TIMEOUT_MS)) == EWOULDBLOCK) {
308 1.2.4.2 perseant sc->sc_error = EIO;
309 1.2.4.2 perseant }
310 1.2.4.2 perseant
311 1.2.4.2 perseant mutex_exit(&sc->sc_mtx);
312 1.2.4.2 perseant
313 1.2.4.2 perseant return sc->sc_error;
314 1.2.4.2 perseant }
315 1.2.4.2 perseant
316 1.2.4.2 perseant static int
317 1.2.4.2 perseant mesoni2c_intr(void *arg)
318 1.2.4.2 perseant {
319 1.2.4.2 perseant struct mesoni2c_softc *sc = arg;
320 1.2.4.2 perseant int done = 0;
321 1.2.4.2 perseant
322 1.2.4.2 perseant mutex_enter(&sc->sc_mtx);
323 1.2.4.2 perseant
324 1.2.4.2 perseant if (RD4(sc, MESONI2C_CTRL_REG) & MESONI2C_CTRL_ERROR) {
325 1.2.4.2 perseant /*
326 1.2.4.2 perseant * The ERROR bit is set when the ACK_IGNORE bit is cleared
327 1.2.4.2 perseant * in MESONI2C_CTRL_REG and the device didn't respond with
328 1.2.4.2 perseant * an ACK. In this case, the I2C controller automatically
329 1.2.4.2 perseant * generates a STOP condition.
330 1.2.4.2 perseant */
331 1.2.4.2 perseant sc->sc_error = EIO;
332 1.2.4.2 perseant done = 1;
333 1.2.4.2 perseant } else {
334 1.2.4.2 perseant if (I2C_OP_READ_P(sc->sc_curop)) {
335 1.2.4.2 perseant /* Read data bytes */
336 1.2.4.2 perseant u_int count = (RD4(sc, MESONI2C_CTRL_REG) & MESONI2C_CTRL_READ_DATA_MASK)
337 1.2.4.2 perseant >> MESONI2C_CTRL_READ_DATA_SHIFT;
338 1.2.4.2 perseant
339 1.2.4.2 perseant while (count--) {
340 1.2.4.2 perseant *(sc->sc_databuf++) = mesoni2c_get_byte(sc);
341 1.2.4.2 perseant }
342 1.2.4.2 perseant }
343 1.2.4.2 perseant
344 1.2.4.2 perseant if (sc->sc_curlen) {
345 1.2.4.2 perseant /* Continue transfer */
346 1.2.4.2 perseant mesoni2c_reset_state(sc);
347 1.2.4.2 perseant mesoni2c_partial_xfer(sc);
348 1.2.4.2 perseant } else {
349 1.2.4.2 perseant if (sc->sc_sendingCmd && sc->sc_datalen) {
350 1.2.4.2 perseant /*
351 1.2.4.2 perseant * We've just finished transfering the command
352 1.2.4.2 perseant * bytes, we must now tranfer the data.
353 1.2.4.2 perseant */
354 1.2.4.2 perseant sc->sc_curlen = sc->sc_datalen;
355 1.2.4.2 perseant sc->sc_curop = sc->sc_op;
356 1.2.4.2 perseant sc->sc_sendingCmd = 0;
357 1.2.4.2 perseant
358 1.2.4.2 perseant if (I2C_OP_READ_P(sc->sc_curop)) {
359 1.2.4.2 perseant mesoni2c_prepare_xfer(sc, sc->sc_curop);
360 1.2.4.2 perseant } else {
361 1.2.4.2 perseant mesoni2c_reset_state(sc);
362 1.2.4.2 perseant }
363 1.2.4.2 perseant
364 1.2.4.2 perseant mesoni2c_partial_xfer(sc);
365 1.2.4.2 perseant } else {
366 1.2.4.2 perseant done = 1;
367 1.2.4.2 perseant }
368 1.2.4.2 perseant }
369 1.2.4.2 perseant }
370 1.2.4.2 perseant
371 1.2.4.2 perseant if (done) {
372 1.2.4.2 perseant /* Tell mesoni2c_exec() we're done. */
373 1.2.4.2 perseant cv_broadcast(&sc->sc_cv);
374 1.2.4.2 perseant }
375 1.2.4.2 perseant
376 1.2.4.2 perseant mutex_exit(&sc->sc_mtx);
377 1.2.4.2 perseant
378 1.2.4.2 perseant return 1;
379 1.2.4.2 perseant }
380 1.2.4.2 perseant
381 1.2.4.2 perseant static void
382 1.2.4.2 perseant mesoni2c_set_clock_div_meson6(struct mesoni2c_softc *sc)
383 1.2.4.2 perseant {
384 1.2.4.2 perseant u_int rate = clk_get_rate(sc->sc_clk);
385 1.2.4.2 perseant u_int div = howmany(rate, sc->sc_clkfreq) - FILTER_DELAY;
386 1.2.4.2 perseant div = howmany(div, 4);
387 1.2.4.2 perseant
388 1.2.4.2 perseant /* Set prescaler */
389 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIV_MASK, (div & __BITS(9, 0)) << MESONI2C_CTRL_CLKDIV_SHIFT);
390 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIVEXT_MASK, (div >> 10) << MESONI2C_CTRL_CLKDIVEXT_SHIFT);
391 1.2.4.2 perseant
392 1.2.4.2 perseant /* Disable HIGH/LOW mode */
393 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_EN, 0);
394 1.2.4.2 perseant }
395 1.2.4.2 perseant
396 1.2.4.2 perseant static void
397 1.2.4.2 perseant mesoni2c_set_clock_div_gxbb_axg(struct mesoni2c_softc *sc)
398 1.2.4.2 perseant {
399 1.2.4.2 perseant u_int rate = clk_get_rate(sc->sc_clk);
400 1.2.4.2 perseant u_int divh, divl;
401 1.2.4.2 perseant
402 1.2.4.2 perseant /*
403 1.2.4.2 perseant * According to I2C-BUS Spec 2.1, in FAST-MODE, the minimum
404 1.2.4.2 perseant * LOW period is 1.3uS, and minimum HIGH is least 0.6us.
405 1.2.4.2 perseant * For
406 1.2.4.2 perseant * 400000 freq, the period is 2.5us. To keep within the specs,
407 1.2.4.2 perseant * give 40% of period to HIGH and 60% to LOW. This means HIGH
408 1.2.4.2 perseant * at 1.0us and LOW 1.5us.
409 1.2.4.2 perseant * The same applies for Fast-mode plus, where LOW is 0.5us and
410 1.2.4.2 perseant * HIGH is 0.26us.
411 1.2.4.2 perseant * Duty = H/(H + L) = 2/5
412 1.2.4.2 perseant */
413 1.2.4.2 perseant if (sc->sc_clkfreq <= 100000) {
414 1.2.4.2 perseant divh = howmany(rate, sc->sc_clkfreq);
415 1.2.4.2 perseant divl = howmany(divh, 4);
416 1.2.4.2 perseant divh = howmany(divh, 2) - FILTER_DELAY;
417 1.2.4.2 perseant } else {
418 1.2.4.2 perseant divh = howmany(rate * 2, sc->sc_clkfreq * 5) - FILTER_DELAY;
419 1.2.4.2 perseant divl = howmany(rate * 3, sc->sc_clkfreq * 5 * 2);
420 1.2.4.2 perseant }
421 1.2.4.2 perseant
422 1.2.4.2 perseant /* Set prescaler */
423 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIV_MASK, (divh & __BITS(9, 0)) << MESONI2C_CTRL_CLKDIV_SHIFT);
424 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIVEXT_MASK, (divh >> 10) << MESONI2C_CTRL_CLKDIVEXT_SHIFT);
425 1.2.4.2 perseant
426 1.2.4.2 perseant /* Set SCL low delay */
427 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_MASK, divl << MESONI2C_SLAVE_SCL_LOW_SHIFT);
428 1.2.4.2 perseant
429 1.2.4.2 perseant /* Enable HIGH/LOW mode */
430 1.2.4.2 perseant mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_EN, MESONI2C_SLAVE_SCL_LOW_EN);
431 1.2.4.2 perseant }
432 1.2.4.2 perseant
433 1.2.4.2 perseant static int
434 1.2.4.2 perseant mesoni2c_match(device_t parent, cfdata_t cf, void *aux)
435 1.2.4.2 perseant {
436 1.2.4.2 perseant struct fdt_attach_args * const faa = aux;
437 1.2.4.2 perseant
438 1.2.4.2 perseant return of_compatible_match(faa->faa_phandle, compat_data);
439 1.2.4.2 perseant }
440 1.2.4.2 perseant
441 1.2.4.2 perseant static void
442 1.2.4.2 perseant mesoni2c_attach(device_t parent, device_t self, void *aux)
443 1.2.4.2 perseant {
444 1.2.4.2 perseant struct mesoni2c_softc * const sc = device_private(self);
445 1.2.4.2 perseant struct fdt_attach_args * const faa = aux;
446 1.2.4.2 perseant const int phandle = faa->faa_phandle;
447 1.2.4.2 perseant bus_addr_t addr;
448 1.2.4.2 perseant bus_size_t size;
449 1.2.4.2 perseant char intrstr[128];
450 1.2.4.2 perseant
451 1.2.4.2 perseant if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
452 1.2.4.2 perseant aprint_error_dev(self, "couldn't get registers\n");
453 1.2.4.2 perseant return;
454 1.2.4.2 perseant }
455 1.2.4.2 perseant
456 1.2.4.2 perseant sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
457 1.2.4.2 perseant
458 1.2.4.2 perseant if (sc->sc_clk == NULL || clk_enable(sc->sc_clk) != 0) {
459 1.2.4.2 perseant aprint_error_dev(self, "couldn't enable clock\n");
460 1.2.4.2 perseant return;
461 1.2.4.2 perseant }
462 1.2.4.2 perseant
463 1.2.4.2 perseant sc->sc_dev = self;
464 1.2.4.2 perseant sc->sc_bst = faa->faa_bst;
465 1.2.4.2 perseant
466 1.2.4.2 perseant if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
467 1.2.4.2 perseant aprint_error_dev(self, "couldn't map registers\n");
468 1.2.4.2 perseant return;
469 1.2.4.2 perseant }
470 1.2.4.2 perseant
471 1.2.4.2 perseant fdtbus_clock_assign(phandle);
472 1.2.4.2 perseant
473 1.2.4.2 perseant if (of_getprop_uint32(phandle, "clock-frequency", &sc->sc_clkfreq)) {
474 1.2.4.2 perseant sc->sc_clkfreq = 100000;
475 1.2.4.2 perseant } else {
476 1.2.4.2 perseant if (sc->sc_clkfreq < 100000) {
477 1.2.4.2 perseant sc->sc_clkfreq = 100000;
478 1.2.4.2 perseant } else if (sc->sc_clkfreq > 400000) {
479 1.2.4.2 perseant sc->sc_clkfreq = 400000;
480 1.2.4.2 perseant }
481 1.2.4.2 perseant }
482 1.2.4.2 perseant
483 1.2.4.2 perseant aprint_naive("\n");
484 1.2.4.2 perseant aprint_normal(": Meson I2C (%u Hz)\n", sc->sc_clkfreq);
485 1.2.4.2 perseant
486 1.2.4.2 perseant enum mesoni2c_type type = of_compatible_lookup(phandle, compat_data)->value;
487 1.2.4.2 perseant
488 1.2.4.2 perseant switch (type) {
489 1.2.4.2 perseant case TYPE_MESON6:
490 1.2.4.2 perseant mesoni2c_set_clock_div_meson6(sc);
491 1.2.4.2 perseant break;
492 1.2.4.2 perseant
493 1.2.4.2 perseant case TYPE_GXBB:
494 1.2.4.2 perseant case TYPE_AXG:
495 1.2.4.2 perseant mesoni2c_set_clock_div_gxbb_axg(sc);
496 1.2.4.2 perseant break;
497 1.2.4.2 perseant }
498 1.2.4.2 perseant
499 1.2.4.2 perseant mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
500 1.2.4.2 perseant cv_init(&sc->sc_cv, "mesoniic");
501 1.2.4.2 perseant
502 1.2.4.2 perseant if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
503 1.2.4.2 perseant aprint_error_dev(self, "failed to decode interrupt\n");
504 1.2.4.2 perseant return;
505 1.2.4.2 perseant }
506 1.2.4.2 perseant
507 1.2.4.2 perseant sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 0,
508 1.2.4.2 perseant mesoni2c_intr, sc, device_xname(self));
509 1.2.4.2 perseant
510 1.2.4.2 perseant if (sc->sc_ih == NULL) {
511 1.2.4.2 perseant aprint_error_dev(self, "couldn't establish interrupt\n");
512 1.2.4.2 perseant return;
513 1.2.4.2 perseant }
514 1.2.4.2 perseant
515 1.2.4.2 perseant aprint_normal_dev(self, "interrupting on %s\n", intrstr);
516 1.2.4.2 perseant
517 1.2.4.2 perseant iic_tag_init(&sc->sc_ic);
518 1.2.4.2 perseant sc->sc_ic.ic_cookie = sc;
519 1.2.4.2 perseant sc->sc_ic.ic_exec = mesoni2c_exec;
520 1.2.4.2 perseant fdtbus_register_i2c_controller(&sc->sc_ic, phandle);
521 1.2.4.2 perseant
522 1.2.4.2 perseant fdtbus_attach_i2cbus(self, phandle, &sc->sc_ic, iicbus_print);
523 1.2.4.2 perseant }
524