pca9564.c revision 1.6 1 /* $NetBSD: pca9564.c,v 1.6 2025/09/15 13:23:03 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2010 NONAKA Kimihiro <nonaka (at) netbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: pca9564.c,v 1.6 2025/09/15 13:23:03 thorpej Exp $");
30
31 #include <sys/param.h>
32 #include <sys/device.h>
33 #include <sys/mutex.h>
34 #include <sys/bus.h>
35
36 #include <dev/i2c/i2cvar.h>
37
38 #include <dev/ic/pca9564reg.h>
39 #include <dev/ic/pca9564var.h>
40
41 #if defined(PCA9564_DEBUG)
42 int pca9564debug = 0;
43 #define DPRINTF(s) if (pca9564debug) printf s
44 #else
45 #define DPRINTF(s)
46 #endif
47
48 static int pca9564_acquire_bus(void *, int);
49 static void pca9564_release_bus(void *, int);
50
51 static int pca9564_send_start(void *, int);
52 static int pca9564_send_stop(void *, int);
53 static int pca9564_initiate_xfer(void *, uint16_t, int);
54 static int pca9564_read_byte(void *, uint8_t *, int);
55 static int pca9564_write_byte(void *, uint8_t, int);
56
57 static int pca9564_ack(void *, bool, int);
58
59 #define CSR_READ(sc, r) (*sc->sc_ios.read_byte)(sc->sc_dev, r)
60 #define CSR_WRITE(sc, r, v) (*sc->sc_ios.write_byte)(sc->sc_dev, r, v)
61
62 void
63 pca9564_attach(struct pca9564_softc *sc)
64 {
65
66 aprint_naive("\n");
67 aprint_normal(": PCA9564 I2C Controller\n");
68
69 iic_tag_init(&sc->sc_i2c);
70 sc->sc_i2c.ic_cookie = sc;
71 sc->sc_i2c.ic_acquire_bus = pca9564_acquire_bus;
72 sc->sc_i2c.ic_release_bus = pca9564_release_bus;
73 sc->sc_i2c.ic_send_start = pca9564_send_start;
74 sc->sc_i2c.ic_send_stop = pca9564_send_stop;
75 sc->sc_i2c.ic_initiate_xfer = pca9564_initiate_xfer;
76 sc->sc_i2c.ic_read_byte = pca9564_read_byte;
77 sc->sc_i2c.ic_write_byte = pca9564_write_byte;
78
79 /* set serial clock rate */
80 switch (sc->sc_i2c_clock) {
81 case 330000: /* 330kHz */
82 sc->sc_i2c_clock = I2CCON_CR_330KHZ;
83 break;
84 case 288000: /* 288kHz */
85 sc->sc_i2c_clock = I2CCON_CR_288KHZ;
86 break;
87 case 217000: /* 217kHz */
88 sc->sc_i2c_clock = I2CCON_CR_217KHZ;
89 break;
90 case 146000: /* 146kHz */
91 sc->sc_i2c_clock = I2CCON_CR_146KHZ;
92 break;
93 case 88000: /* 88kHz */
94 sc->sc_i2c_clock = I2CCON_CR_88KHZ;
95 break;
96 case 0: /* default */
97 case 59000: /* 59kHz */
98 sc->sc_i2c_clock = I2CCON_CR_59KHZ;
99 break;
100 case 44000: /* 44kHz */
101 sc->sc_i2c_clock = I2CCON_CR_44KHZ;
102 break;
103 case 36000: /* 36kHz */
104 sc->sc_i2c_clock = I2CCON_CR_36KHZ;
105 break;
106 default:
107 aprint_error_dev(sc->sc_dev, "unknown i2c clock %dHz\n",
108 sc->sc_i2c_clock);
109 sc->sc_i2c_clock = I2CCON_CR_59KHZ;
110 break;
111 }
112
113 iicbus_attach(sc->sc_dev, &sc->sc_i2c);
114 }
115
116 static int
117 pca9564_acquire_bus(void *cookie, int flags)
118 {
119 struct pca9564_softc *sc = cookie;
120 uint8_t control;
121
122 /* Enable SIO and set clock */
123 control = CSR_READ(sc, PCA9564_I2CCON);
124 control |= I2CCON_ENSIO;
125 control &= ~(I2CCON_STA|I2CCON_STO|I2CCON_SI|I2CCON_AA);
126 control &= ~I2CCON_CR_MASK;
127 control |= sc->sc_i2c_clock;
128 CSR_WRITE(sc, PCA9564_I2CCON, control);
129 delay(500);
130
131 return 0;
132 }
133
134 static void
135 pca9564_release_bus(void *cookie, int flags)
136 {
137 struct pca9564_softc *sc = cookie;
138 uint8_t control;
139
140 /* Disable SIO */
141 control = CSR_READ(sc, PCA9564_I2CCON);
142 control &= ~I2CCON_ENSIO;
143 CSR_WRITE(sc, PCA9564_I2CCON, control);
144 }
145
146 #define PCA9564_TIMEOUT 100 /* protocol timeout, in uSecs */
147
148 static int
149 pca9564_wait(struct pca9564_softc *sc, int flags)
150 {
151 int timeout;
152
153 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
154 for (timeout = PCA9564_TIMEOUT; timeout > 0; timeout--) {
155 if (CSR_READ(sc, PCA9564_I2CCON) & I2CCON_SI)
156 break;
157 delay(1);
158 }
159 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
160 if (timeout == 0) {
161 aprint_error_dev(sc->sc_dev, "timeout\n");
162 return ETIMEDOUT;
163 }
164 return 0;
165 }
166
167 static int
168 pca9564_send_start(void *cookie, int flags)
169 {
170 struct pca9564_softc *sc = cookie;
171 uint8_t control;
172
173 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
174 control = CSR_READ(sc, PCA9564_I2CCON);
175 control |= I2CCON_STA;
176 control &= ~(I2CCON_STO|I2CCON_SI);
177 CSR_WRITE(sc, PCA9564_I2CCON, control);
178 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
179
180 return pca9564_wait(sc, flags);
181 }
182
183 static int
184 pca9564_send_stop(void *cookie, int flags)
185 {
186 struct pca9564_softc *sc = cookie;
187 uint8_t control;
188
189 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
190 control = CSR_READ(sc, PCA9564_I2CCON);
191 control |= I2CCON_STO;
192 control &= ~(I2CCON_STA|I2CCON_SI);
193 CSR_WRITE(sc, PCA9564_I2CCON, control);
194 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
195
196 return 0;
197 }
198
199 static int
200 pca9564_initiate_xfer(void *cookie, uint16_t addr, int flags)
201 {
202 struct pca9564_softc *sc = cookie;
203 int error, rd_req = (flags & I2C_F_READ) != 0;
204 uint8_t data, control;
205
206 error = pca9564_send_start(sc, flags);
207 if (error) {
208 aprint_error_dev(sc->sc_dev, "failed to send start %s xfer\n",
209 rd_req ? "read" : "write");
210 return error;
211 }
212
213 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
214 control = CSR_READ(sc, PCA9564_I2CCON);
215
216 data = (addr << 1) | (rd_req ? 1 : 0);
217 CSR_WRITE(sc, PCA9564_I2CDAT, data);
218
219 control &= ~(I2CCON_STO|I2CCON_STA|I2CCON_SI);
220 CSR_WRITE(sc, PCA9564_I2CCON, control);
221 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
222
223 error = pca9564_wait(sc, flags);
224 if (error)
225 aprint_error_dev(sc->sc_dev, "failed to initiate %s xfer\n",
226 rd_req ? "read" : "write");
227 return error;
228 }
229
230 static int
231 pca9564_read_byte(void *cookie, uint8_t *bytep, int flags)
232 {
233 struct pca9564_softc *sc = cookie;
234 int send_stop = (flags & I2C_F_STOP) != 0;
235 int error;
236
237 error = pca9564_ack(sc, !send_stop, flags);
238 if (error) {
239 aprint_error_dev(sc->sc_dev, "failed to ack\n");
240 return error;
241 }
242
243 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
244 *bytep = CSR_READ(sc, PCA9564_I2CDAT);
245 DPRINTF(("%s: status=%#x, byte=%#x\n", __func__,
246 CSR_READ(sc, PCA9564_I2CSTA), *bytep));
247
248 if (send_stop)
249 pca9564_send_stop(sc, flags);
250
251 return 0;
252 }
253
254 static int
255 pca9564_write_byte(void *cookie, uint8_t byte, int flags)
256 {
257 struct pca9564_softc *sc = cookie;
258 int send_stop = (flags & I2C_F_STOP) != 0;
259 int error;
260 uint8_t control;
261
262 DPRINTF(("%s: status=%#x, byte=%#x\n", __func__,
263 CSR_READ(sc, PCA9564_I2CSTA), byte));
264 control = CSR_READ(sc, PCA9564_I2CCON);
265
266 CSR_WRITE(sc, PCA9564_I2CDAT, byte);
267
268 control &= ~(I2CCON_STO|I2CCON_STA|I2CCON_SI);
269 CSR_WRITE(sc, PCA9564_I2CCON, control);
270 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
271
272 error = pca9564_wait(sc, flags);
273 if (error)
274 aprint_error_dev(sc->sc_dev, "write byte failed\n");
275
276 if (send_stop)
277 pca9564_send_stop(sc, flags);
278
279 return error;
280 }
281
282 static int
283 pca9564_ack(void *cookie, bool ack, int flags)
284 {
285 struct pca9564_softc *sc = cookie;
286 uint8_t control;
287
288 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
289 control = CSR_READ(sc, PCA9564_I2CCON);
290 control &= ~(I2CCON_STO|I2CCON_STA|I2CCON_SI|I2CCON_AA);
291 if (ack)
292 control |= I2CCON_AA;
293 CSR_WRITE(sc, PCA9564_I2CCON, control);
294 DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA)));
295
296 return pca9564_wait(sc, flags);
297 }
298