xref: /netbsd-src/sys/dev/i2c/cx24227.c (revision 853e179a3c6ef685fd9cd5f3c466ff68ae01352b)
1 /* $NetBSD: cx24227.c,v 1.11 2019/12/31 14:25:33 thorpej 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.11 2019/12/31 14:25:33 thorpej 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 ((error = iic_acquire_bus(sc->tag, 0)) != 0)
112 		return error;
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, 0);
119 
120 	iic_release_bus(sc->tag, 0);
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 ((error = iic_acquire_bus(sc->tag, 0)) != 0)
134 		return error;
135 
136 	error = iic_exec(sc->tag, I2C_OP_READ_WITH_STOP, sc->addr,
137 			 &reg, 1, r, 2, 0);
138 
139 	iic_release_bus(sc->tag, 0);
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, &reg);
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 	sc->parent = parent;
238 	sc->tag = tag;
239 	sc->addr = addr;
240 
241 	/* read chip ids */
242 	value = 0;
243 	e = cx24227_readreg(sc, 0x04, &value);
244 	if (e) {
245 		device_printf(parent, "cx24227: read failed: %d\n", e);
246 		kmem_free(sc, sizeof(*sc));
247 		return NULL;
248 	}
249 #ifdef CX24227_DEBUG
250 	device_printf(parent, "cx24227: chipid %04x\n", value);
251 #endif
252 
253 
254 	value = 0x0001; /* open the i2c gate */
255 	e = cx24227_writereg(sc, 0xf3, value);
256 #if 0
257 	if (e) {
258 		device_printf(parent, "cx24227: write failed: %d\n", e);
259 		kmem_free(sc, sizeof(*sc));
260 		return NULL;
261 	}
262 #endif
263 
264 	cx24227_init(sc);
265 
266 	return sc;
267 }
268 
269 void
cx24227_close(struct cx24227 * sc)270 cx24227_close(struct cx24227 *sc)
271 {
272 	kmem_free(sc, sizeof(*sc));
273 }
274 
275 
276 static void
cx24227_sleepreset(struct cx24227 * sc)277 cx24227_sleepreset(struct cx24227 *sc)
278 {
279 	cx24227_writereg(sc, 0xf2, 0);
280 	cx24227_writereg(sc, 0xfa, 0);
281 }
282 
283 static int
cx24227_init(struct cx24227 * sc)284 cx24227_init(struct cx24227 *sc)
285 {
286 	unsigned int i;
287 	uint16_t reg;
288 
289 	cx24227_sleepreset(sc);
290 
291 	for(i = 0; i < __arraycount(documentation_wanted); i++)
292 		cx24227_writereg(sc, documentation_wanted[i].r, documentation_wanted[i].v);
293 
294 	/* Serial */
295 	cx24227_readreg(sc, 0xab, &reg);
296 	reg |= 0x0100;
297 	cx24227_writereg(sc, 0xab, reg);
298 
299 	/* no spectral inversion */
300 	cx24227_writereg(sc, 0x1b, 0x0110);
301 
302 	/* 44MHz IF */
303 	cx24227_writereg(sc, 0x87, 0x01be);
304 	cx24227_writereg(sc, 0x88, 0x0436);
305 	cx24227_writereg(sc, 0x89, 0x054d);
306 
307 	/* GPIO on */
308 	cx24227_readreg(sc, 0xe3, &reg);
309 	reg |= 0x1100;
310 	cx24227_writereg(sc, 0xe3, reg);
311 
312 	/* clocking */
313 	cx24227_readreg(sc, 0xac, &reg);
314 	reg &= ~0x3000;
315 	reg |= 0x1000;
316 	cx24227_writereg(sc, 0xac, reg);
317 
318 	/* soft reset */
319 	cx24227_writereg(sc, 0xf5, 0x0000);
320 	cx24227_writereg(sc, 0xf5, 0x0001);
321 
322 	/* open gate */
323 	cx24227_writereg(sc, 0xf3, 0x0001);
324 
325 	return 0;
326 }
327 
328 MODULE(MODULE_CLASS_DRIVER, cx24227, "i2cexec");
329 
330 static int
cx24227_modcmd(modcmd_t cmd,void * priv)331 cx24227_modcmd(modcmd_t cmd, void *priv)
332 {
333 	if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI)
334 		return 0;
335 	return ENOTTY;
336 }
337