1 /* $NetBSD: cx24227.c,v 1.7 2015/03/07 14:16:51 jmcneill Exp $ */
2
3 /*
4 * Copyright (c) 2008, 2011 Jonathan A. Kollasch
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 COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: cx24227.c,v 1.7 2015/03/07 14:16:51 jmcneill Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 #include <sys/kmem.h>
36 #include <sys/module.h>
37
38 #include <dev/i2c/cx24227var.h>
39
40 /* #define CX24227_DEBUG */
41
42 struct cx24227 {
43 device_t parent;
44 i2c_tag_t tag;
45 i2c_addr_t addr;
46 };
47
48 static int cx24227_writereg(struct cx24227 *, uint8_t, uint16_t);
49 static int cx24227_readreg(struct cx24227 *, uint8_t, uint16_t *);
50
51 static int cx24227_init(struct cx24227 *);
52
53 static struct documentation_wanted {
54 uint8_t r;
55 uint16_t v;
56 } documentation_wanted[] = {
57 { 0x00, 0x0071, },
58 { 0x01, 0x3213, },
59 { 0x09, 0x0025, },
60 { 0x1c, 0x001d, },
61 { 0x1f, 0x002d, },
62 { 0x20, 0x001d, },
63 { 0x22, 0x0022, },
64 { 0x23, 0x0020, },
65 { 0x29, 0x110f, },
66 { 0x2a, 0x10b4, },
67 { 0x2b, 0x10ae, },
68 { 0x2c, 0x0031, },
69 { 0x31, 0x010d, },
70 { 0x32, 0x0100, },
71 { 0x44, 0x0510, },
72 { 0x54, 0x0104, },
73 { 0x58, 0x2222, },
74 { 0x59, 0x1162, },
75 { 0x5a, 0x3211, },
76 { 0x5d, 0x0370, },
77 { 0x5e, 0x0296, },
78 { 0x61, 0x0010, },
79 { 0x63, 0x4a00, },
80 { 0x65, 0x0800, },
81 { 0x71, 0x0003, },
82 { 0x72, 0x0470, },
83 { 0x81, 0x0002, },
84 { 0x82, 0x0600, },
85 { 0x86, 0x0002, },
86 { 0x8a, 0x2c38, },
87 { 0x8b, 0x2a37, },
88 { 0x92, 0x302f, },
89 { 0x93, 0x3332, },
90 { 0x96, 0x000c, },
91 { 0x99, 0x0101, },
92 { 0x9c, 0x2e37, },
93 { 0x9d, 0x2c37, },
94 { 0x9e, 0x2c37, },
95 { 0xab, 0x0100, },
96 { 0xac, 0x1003, },
97 { 0xad, 0x103f, },
98 { 0xe2, 0x0100, },
99 { 0xe3, 0x1000, },
100 { 0x28, 0x1010, },
101 { 0xb1, 0x000e, },
102 };
103
104
105 static int
cx24227_writereg(struct cx24227 * sc,uint8_t reg,uint16_t data)106 cx24227_writereg(struct cx24227 *sc, uint8_t reg, uint16_t data)
107 {
108 int error;
109 uint8_t r[3];
110
111 if (iic_acquire_bus(sc->tag, I2C_F_POLL) != 0)
112 return false;
113
114 r[0] = reg;
115 r[1] = (data >> 8) & 0xff;
116 r[2] = data & 0xff;
117 error = iic_exec(sc->tag, I2C_OP_WRITE_WITH_STOP, sc->addr,
118 r, 3, NULL, 0, I2C_F_POLL);
119
120 iic_release_bus(sc->tag, I2C_F_POLL);
121
122 return error;
123 }
124
125 static int
cx24227_readreg(struct cx24227 * sc,uint8_t reg,uint16_t * data)126 cx24227_readreg(struct cx24227 *sc, uint8_t reg, uint16_t *data)
127 {
128 int error;
129 uint8_t r[2];
130
131 *data = 0x0000;
132
133 if (iic_acquire_bus(sc->tag, I2C_F_POLL) != 0)
134 return -1;
135
136 error = iic_exec(sc->tag, I2C_OP_READ_WITH_STOP, sc->addr,
137 ®, 1, r, 2, I2C_F_POLL);
138
139 iic_release_bus(sc->tag, I2C_F_POLL);
140
141 *data |= r[0] << 8;
142 *data |= r[1];
143
144 return error;
145 }
146
147 uint16_t
cx24227_get_signal(struct cx24227 * sc)148 cx24227_get_signal(struct cx24227 *sc)
149 {
150 uint16_t sig = 0;
151
152 cx24227_readreg(sc, 0xf1, &sig);
153
154 return sig;
155 }
156
157 fe_status_t
cx24227_get_dtv_status(struct cx24227 * sc)158 cx24227_get_dtv_status(struct cx24227 *sc)
159 {
160 uint16_t reg;
161 fe_status_t status = 0;
162
163 cx24227_readreg(sc, 0xf1, ®);
164
165 if(reg & 0x1000)
166 status = FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
167 if(reg & 0x8000)
168 status |= FE_HAS_LOCK | FE_HAS_SYNC;
169
170 return status;
171 }
172
173 int
cx24227_set_modulation(struct cx24227 * sc,fe_modulation_t modulation)174 cx24227_set_modulation(struct cx24227 *sc, fe_modulation_t modulation)
175 {
176 switch (modulation) {
177 case VSB_8:
178 case QAM_64:
179 case QAM_256:
180 case QAM_AUTO:
181 break;
182 default:
183 return EINVAL;
184 }
185
186 /* soft reset */
187 cx24227_writereg(sc, 0xf5, 0x0000);
188 cx24227_writereg(sc, 0xf5, 0x0001);
189
190 switch (modulation) {
191 case VSB_8:
192 /* VSB8 */
193 cx24227_writereg(sc, 0xf4, 0x0000);
194 break;
195 default:
196 /* QAM */
197 cx24227_writereg(sc, 0xf4, 0x0001);
198 cx24227_writereg(sc, 0x85, 0x0110);
199 break;
200 }
201
202 /* soft reset */
203 cx24227_writereg(sc, 0xf5, 0x0000);
204 cx24227_writereg(sc, 0xf5, 0x0001);
205
206 #if 0
207 delay(100);
208
209 /* open the i2c gate */
210 cx24227_writereg(sc, 0xf3, 0x0001);
211
212 /* we could tune in here? */
213
214 /* close the i2c gate */
215 cx24227_writereg(sc, 0xf3, 0x0000);
216
217 #endif
218 return 0;
219 }
220
221 void
cx24227_enable(struct cx24227 * sc,bool enable)222 cx24227_enable(struct cx24227* sc, bool enable)
223 {
224 if (enable == true) {
225 cx24227_init(sc);
226 }
227 }
228
229 struct cx24227 *
cx24227_open(device_t parent,i2c_tag_t tag,i2c_addr_t addr)230 cx24227_open(device_t parent, i2c_tag_t tag, i2c_addr_t addr)
231 {
232 struct cx24227 *sc;
233 int e;
234 uint16_t value;
235
236 sc = kmem_alloc(sizeof(*sc), KM_SLEEP);
237 if (sc == NULL)
238 return NULL;
239
240 sc->parent = parent;
241 sc->tag = tag;
242 sc->addr = addr;
243
244 /* read chip ids */
245 value = 0;
246 e = cx24227_readreg(sc, 0x04, &value);
247 if (e) {
248 device_printf(parent, "cx24227: read failed: %d\n", e);
249 kmem_free(sc, sizeof(*sc));
250 return NULL;
251 }
252 #ifdef CX24227_DEBUG
253 device_printf(parent, "cx24227: chipid %04x\n", value);
254 #endif
255
256
257 value = 0x0001; /* open the i2c gate */
258 e = cx24227_writereg(sc, 0xf3, value);
259 #if 0
260 if (e) {
261 device_printf(parent, "cx24227: write failed: %d\n", e);
262 kmem_free(sc, sizeof(*sc));
263 return NULL;
264 }
265 #endif
266
267 cx24227_init(sc);
268
269 return sc;
270 }
271
272 void
cx24227_close(struct cx24227 * sc)273 cx24227_close(struct cx24227 *sc)
274 {
275 kmem_free(sc, sizeof(*sc));
276 }
277
278
279 static void
cx24227_sleepreset(struct cx24227 * sc)280 cx24227_sleepreset(struct cx24227 *sc)
281 {
282 cx24227_writereg(sc, 0xf2, 0);
283 cx24227_writereg(sc, 0xfa, 0);
284 }
285
286 static int
cx24227_init(struct cx24227 * sc)287 cx24227_init(struct cx24227 *sc)
288 {
289 unsigned int i;
290 uint16_t reg;
291
292 cx24227_sleepreset(sc);
293
294 for(i = 0; i < __arraycount(documentation_wanted); i++)
295 cx24227_writereg(sc, documentation_wanted[i].r, documentation_wanted[i].v);
296
297 /* Serial */
298 cx24227_readreg(sc, 0xab, ®);
299 reg |= 0x0100;
300 cx24227_writereg(sc, 0xab, reg);
301
302 /* no spectral inversion */
303 cx24227_writereg(sc, 0x1b, 0x0110);
304
305 /* 44MHz IF */
306 cx24227_writereg(sc, 0x87, 0x01be);
307 cx24227_writereg(sc, 0x88, 0x0436);
308 cx24227_writereg(sc, 0x89, 0x054d);
309
310 /* GPIO on */
311 cx24227_readreg(sc, 0xe3, ®);
312 reg |= 0x1100;
313 cx24227_writereg(sc, 0xe3, reg);
314
315 /* clocking */
316 cx24227_readreg(sc, 0xac, ®);
317 reg &= ~0x3000;
318 reg |= 0x1000;
319 cx24227_writereg(sc, 0xac, reg);
320
321 /* soft reset */
322 cx24227_writereg(sc, 0xf5, 0x0000);
323 cx24227_writereg(sc, 0xf5, 0x0001);
324
325 /* open gate */
326 cx24227_writereg(sc, 0xf3, 0x0001);
327
328 return 0;
329 }
330
331 MODULE(MODULE_CLASS_DRIVER, cx24227, "i2cexec");
332
333 static int
cx24227_modcmd(modcmd_t cmd,void * priv)334 cx24227_modcmd(modcmd_t cmd, void *priv)
335 {
336 if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI)
337 return 0;
338 return ENOTTY;
339 }
340