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 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 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 ®, 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 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 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 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 222 cx24227_enable(struct cx24227* sc, bool enable) 223 { 224 if (enable == true) { 225 cx24227_init(sc); 226 } 227 } 228 229 struct cx24227 * 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 270 cx24227_close(struct cx24227 *sc) 271 { 272 kmem_free(sc, sizeof(*sc)); 273 } 274 275 276 static void 277 cx24227_sleepreset(struct cx24227 *sc) 278 { 279 cx24227_writereg(sc, 0xf2, 0); 280 cx24227_writereg(sc, 0xfa, 0); 281 } 282 283 static int 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, ®); 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, ®); 309 reg |= 0x1100; 310 cx24227_writereg(sc, 0xe3, reg); 311 312 /* clocking */ 313 cx24227_readreg(sc, 0xac, ®); 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 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