1/* $NetBSD: cx24227.c,v 1.4 2011/08/05 21:19:23 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.4 2011/08/05 21:19:23 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 42struct cx24227 { 43 device_t parent; 44 i2c_tag_t tag; 45 i2c_addr_t addr; 46}; 47 48static int cx24227_writereg(struct cx24227 *, uint8_t, uint16_t); 49static int cx24227_readreg(struct cx24227 *, uint8_t, uint16_t *); 50 51static int cx24227_init(struct cx24227 *); 52 53static 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 105static int 106cx24227_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 125static int 126cx24227_readreg(struct cx24227 *sc, uint8_t reg, uint16_t *data) 127{ 128 int error; 129 uint8_t r[2]; 130 131 if (iic_acquire_bus(sc->tag, I2C_F_POLL) != 0) 132 return -1; 133 134 *data = 0x0000; 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 147uint16_t 148cx24227_get_signal(struct cx24227 *sc) 149{ 150 uint16_t sig = 0; 151 152 cx24227_readreg(sc, 0xf1, &sig); 153 154 return sig; 155} 156 157fe_status_t 158cx24227_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 173int 174cx24227_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 221void 222cx24227_enable(struct cx24227* sc, bool enable) 223{ 224 if (enable == true) { 225 cx24227_init(sc); 226 } 227} 228 229struct cx24227 * 230cx24227_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 272void 273cx24227_close(struct cx24227 *sc) 274{ 275 kmem_free(sc, sizeof(*sc)); 276} 277 278 279static void 280cx24227_sleepreset(struct cx24227 *sc) 281{ 282 cx24227_writereg(sc, 0xf2, 0); 283 cx24227_writereg(sc, 0xfa, 0); 284} 285 286static int 287cx24227_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 331MODULE(MODULE_CLASS_DRIVER, cx24227, "iic"); 332 333static int 334cx24227_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