1 1.7 thorpej /* $NetBSD: mt2131.c,v 1.7 2019/12/23 18:57:30 thorpej Exp $ */ 2 1.1 jakllsch 3 1.1 jakllsch /* 4 1.1 jakllsch * Copyright (c) 2008, 2011 Jonathan A. Kollasch 5 1.1 jakllsch * All rights reserved. 6 1.1 jakllsch * 7 1.1 jakllsch * Redistribution and use in source and binary forms, with or without 8 1.1 jakllsch * modification, are permitted provided that the following conditions 9 1.1 jakllsch * are met: 10 1.1 jakllsch * 1. Redistributions of source code must retain the above copyright 11 1.1 jakllsch * notice, this list of conditions and the following disclaimer. 12 1.1 jakllsch * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jakllsch * notice, this list of conditions and the following disclaimer in the 14 1.1 jakllsch * documentation and/or other materials provided with the distribution. 15 1.1 jakllsch * 16 1.1 jakllsch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 1.1 jakllsch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 jakllsch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 jakllsch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20 1.1 jakllsch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 1.1 jakllsch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 1.1 jakllsch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 1.1 jakllsch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 1.1 jakllsch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 1.1 jakllsch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 1.1 jakllsch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 jakllsch */ 28 1.1 jakllsch 29 1.1 jakllsch #include <sys/cdefs.h> 30 1.7 thorpej __KERNEL_RCSID(0, "$NetBSD: mt2131.c,v 1.7 2019/12/23 18:57:30 thorpej Exp $"); 31 1.1 jakllsch 32 1.1 jakllsch #include <sys/param.h> 33 1.1 jakllsch #include <sys/systm.h> 34 1.1 jakllsch #include <sys/device.h> 35 1.1 jakllsch #include <sys/kmem.h> 36 1.1 jakllsch #include <sys/syslog.h> 37 1.1 jakllsch #include <sys/proc.h> 38 1.2 jmcneill #include <sys/module.h> 39 1.1 jakllsch 40 1.1 jakllsch #include <dev/i2c/mt2131var.h> 41 1.1 jakllsch 42 1.1 jakllsch #define PWR 0x07 43 1.1 jakllsch #define UPC_1 0x0b 44 1.1 jakllsch #define AGC_RL 0x10 45 1.1 jakllsch #define MISC_2 0x15 46 1.1 jakllsch 47 1.1 jakllsch #define IF1 1220 48 1.1 jakllsch #define IF2 44000 49 1.1 jakllsch #define REF 16000 50 1.1 jakllsch 51 1.1 jakllsch static const uint8_t mt2131_initstring[] = { 52 1.1 jakllsch 0x01, 53 1.1 jakllsch 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 54 1.1 jakllsch 0xfa, 0x88, 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, 55 1.1 jakllsch 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, 0xff, 0x68, 56 1.1 jakllsch 0xa0, 0xff, 0xdd, 0x00, 0x00 57 1.1 jakllsch }; 58 1.1 jakllsch 59 1.1 jakllsch static const uint8_t mt2131_agcinitstring[] = { 60 1.1 jakllsch AGC_RL, 61 1.1 jakllsch 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 62 1.1 jakllsch }; 63 1.1 jakllsch 64 1.1 jakllsch 65 1.1 jakllsch struct mt2131_softc { 66 1.1 jakllsch device_t parent; 67 1.1 jakllsch i2c_tag_t tag; 68 1.1 jakllsch i2c_addr_t addr; 69 1.1 jakllsch uint32_t frequency; 70 1.1 jakllsch uint32_t bandwidth; 71 1.1 jakllsch }; 72 1.1 jakllsch 73 1.1 jakllsch static int mt2131_init(struct mt2131_softc *); 74 1.1 jakllsch 75 1.1 jakllsch static int mt2131_read(struct mt2131_softc *, uint8_t, uint8_t *); 76 1.1 jakllsch static int mt2131_write(struct mt2131_softc *, uint8_t, uint8_t); 77 1.1 jakllsch 78 1.1 jakllsch struct mt2131_softc * 79 1.1 jakllsch mt2131_open(device_t parent, i2c_tag_t t, i2c_addr_t a) 80 1.1 jakllsch { 81 1.1 jakllsch struct mt2131_softc *sc; 82 1.1 jakllsch int ret; 83 1.3 jakllsch uint8_t cmd, reg; 84 1.1 jakllsch 85 1.1 jakllsch cmd = reg = 0; 86 1.1 jakllsch 87 1.1 jakllsch /* get id reg */ 88 1.7 thorpej ret = iic_acquire_bus(t, 0); 89 1.7 thorpej if (ret == 0) { 90 1.7 thorpej ret = iic_exec(t, I2C_OP_READ_WITH_STOP, a, &cmd, 1, ®, 1, 91 1.7 thorpej 0); 92 1.7 thorpej iic_release_bus(t, 0); 93 1.7 thorpej } 94 1.1 jakllsch 95 1.1 jakllsch if (ret) { 96 1.3 jakllsch device_printf(parent, "%s(): read fail\n", __func__); 97 1.1 jakllsch return NULL; 98 1.1 jakllsch } 99 1.1 jakllsch 100 1.3 jakllsch if ((reg & 0xfe) != 0x3e) { 101 1.3 jakllsch device_printf(parent, "%s(): chip id %02x unknown\n", 102 1.3 jakllsch __func__, reg); 103 1.1 jakllsch return NULL; 104 1.3 jakllsch } 105 1.1 jakllsch 106 1.1 jakllsch sc = kmem_alloc(sizeof(*sc), KM_SLEEP); 107 1.1 jakllsch sc->parent = parent; 108 1.1 jakllsch sc->tag = t; 109 1.1 jakllsch sc->addr = a; 110 1.1 jakllsch 111 1.1 jakllsch mt2131_init(sc); 112 1.1 jakllsch 113 1.1 jakllsch return sc; 114 1.1 jakllsch } 115 1.1 jakllsch 116 1.1 jakllsch void 117 1.1 jakllsch mt2131_close(struct mt2131_softc *sc) 118 1.1 jakllsch { 119 1.1 jakllsch kmem_free(sc, sizeof(*sc)); 120 1.1 jakllsch } 121 1.1 jakllsch 122 1.1 jakllsch int 123 1.1 jakllsch mt2131_tune_dtv(struct mt2131_softc *sc, const struct dvb_frontend_parameters *p) 124 1.1 jakllsch { 125 1.3 jakllsch int rv, i; 126 1.1 jakllsch uint64_t o1, o2; 127 1.1 jakllsch uint64_t d1, d2; 128 1.1 jakllsch uint32_t r1, r2; 129 1.1 jakllsch uint32_t fr; 130 1.1 jakllsch uint8_t b[7]; 131 1.1 jakllsch uint8_t regval; 132 1.1 jakllsch 133 1.1 jakllsch mt2131_init(sc); 134 1.1 jakllsch 135 1.1 jakllsch b[0] = 0x01; 136 1.1 jakllsch 137 1.1 jakllsch if(p->frequency != 0 && 138 1.1 jakllsch (p->frequency < 50000000 || p->frequency > 1000000000)) 139 1.1 jakllsch return EINVAL; 140 1.1 jakllsch 141 1.1 jakllsch fr = p->frequency / 1000; 142 1.1 jakllsch 143 1.1 jakllsch o1 = fr + IF1 * 1000; 144 1.1 jakllsch o2 = o1 - fr - IF2; 145 1.1 jakllsch 146 1.1 jakllsch d1 = (o1 * 8192)/REF; 147 1.1 jakllsch d2 = (o2 * 8192)/REF; 148 1.1 jakllsch 149 1.1 jakllsch r1 = d1/8192; 150 1.1 jakllsch r2 = d2/8192; 151 1.1 jakllsch 152 1.1 jakllsch b[1] = (d1 & 0x1fe0) >> 5; 153 1.1 jakllsch b[2] = (d1 & 0x001f); 154 1.1 jakllsch b[3] = r1; 155 1.1 jakllsch b[4] = (d2 & 0x1fe0) >> 5; 156 1.1 jakllsch b[5] = (d2 & 0x001f); 157 1.1 jakllsch b[6] = r2; 158 1.1 jakllsch 159 1.7 thorpej rv = iic_acquire_bus(sc->tag, 0); 160 1.7 thorpej if (rv == 0) { 161 1.7 thorpej rv = iic_exec(sc->tag, I2C_OP_WRITE_WITH_STOP, sc->addr, b, 7, 162 1.7 thorpej NULL, 0, 0); 163 1.7 thorpej iic_release_bus(sc->tag, 0); 164 1.7 thorpej } 165 1.1 jakllsch 166 1.1 jakllsch regval = (fr - 27501) / 55000; 167 1.1 jakllsch 168 1.1 jakllsch if(regval > 0x13) 169 1.1 jakllsch regval = 0x13; 170 1.1 jakllsch 171 1.1 jakllsch rv = mt2131_write(sc, UPC_1, regval); 172 1.1 jakllsch 173 1.1 jakllsch if (rv != 0) 174 1.3 jakllsch device_printf(sc->parent, "%s write failed\n", __func__); 175 1.1 jakllsch 176 1.1 jakllsch sc->frequency = (o1 - o2 - IF2) * 1000; 177 1.1 jakllsch 178 1.3 jakllsch for (i = 0; i < 100; i++) { 179 1.3 jakllsch kpause("mt2131", true, 1, NULL); 180 1.1 jakllsch 181 1.1 jakllsch rv = mt2131_read(sc, 0x08, ®val); 182 1.3 jakllsch if (rv != 0) 183 1.3 jakllsch device_printf(sc->parent, "%s read failed\n", __func__); 184 1.1 jakllsch 185 1.1 jakllsch if (( regval & 0x88 ) == 0x88 ) { 186 1.3 jakllsch return 0; 187 1.1 jakllsch } 188 1.1 jakllsch } 189 1.1 jakllsch 190 1.3 jakllsch device_printf(sc->parent, "mt2131 not locked, %02x\n", b[1]); 191 1.3 jakllsch 192 1.1 jakllsch return rv; 193 1.1 jakllsch } 194 1.1 jakllsch 195 1.1 jakllsch static int 196 1.1 jakllsch mt2131_init(struct mt2131_softc *sc) 197 1.1 jakllsch { 198 1.1 jakllsch int ret; 199 1.1 jakllsch 200 1.7 thorpej ret = iic_acquire_bus(sc->tag, 0); 201 1.1 jakllsch if (ret) 202 1.1 jakllsch return -1; 203 1.1 jakllsch ret = iic_exec(sc->tag, I2C_OP_WRITE_WITH_STOP, sc->addr, 204 1.7 thorpej mt2131_initstring, sizeof(mt2131_initstring), NULL, 0, 0); 205 1.7 thorpej iic_release_bus(sc->tag, 0); 206 1.1 jakllsch if (ret) 207 1.1 jakllsch return -1; 208 1.1 jakllsch 209 1.1 jakllsch ret = mt2131_write(sc, UPC_1, 0x09); 210 1.1 jakllsch ret = mt2131_write(sc, MISC_2, 0x47); 211 1.1 jakllsch ret = mt2131_write(sc, PWR, 0xf2); 212 1.1 jakllsch ret = mt2131_write(sc, UPC_1, 0x01); 213 1.1 jakllsch 214 1.7 thorpej ret = iic_acquire_bus(sc->tag, 0); 215 1.1 jakllsch if (ret) 216 1.1 jakllsch return -1; 217 1.1 jakllsch ret = iic_exec(sc->tag, I2C_OP_WRITE_WITH_STOP, sc->addr, 218 1.1 jakllsch mt2131_agcinitstring, sizeof(mt2131_agcinitstring), 219 1.7 thorpej NULL, 0, 0); 220 1.7 thorpej iic_release_bus(sc->tag, 0); 221 1.1 jakllsch if (ret) 222 1.1 jakllsch return -1; 223 1.1 jakllsch 224 1.1 jakllsch return 0; 225 1.1 jakllsch } 226 1.1 jakllsch 227 1.1 jakllsch static int 228 1.1 jakllsch mt2131_read(struct mt2131_softc *sc, uint8_t r, uint8_t *v) 229 1.1 jakllsch { 230 1.1 jakllsch int ret; 231 1.1 jakllsch 232 1.7 thorpej ret = iic_acquire_bus(sc->tag, 0); 233 1.1 jakllsch if (ret) 234 1.1 jakllsch return ret; 235 1.1 jakllsch ret = iic_exec(sc->tag, I2C_OP_READ_WITH_STOP, sc->addr, 236 1.7 thorpej &r, 1, v, 1, 0); 237 1.1 jakllsch 238 1.7 thorpej iic_release_bus(sc->tag, 0); 239 1.1 jakllsch 240 1.1 jakllsch return ret; 241 1.1 jakllsch } 242 1.1 jakllsch 243 1.1 jakllsch static int 244 1.1 jakllsch mt2131_write(struct mt2131_softc *sc, uint8_t a, uint8_t v) 245 1.1 jakllsch { 246 1.1 jakllsch int ret; 247 1.1 jakllsch uint8_t b[] = { a, v }; 248 1.1 jakllsch 249 1.7 thorpej ret = iic_acquire_bus(sc->tag, 0); 250 1.1 jakllsch if (ret) 251 1.1 jakllsch return ret; 252 1.1 jakllsch 253 1.1 jakllsch ret = iic_exec(sc->tag, I2C_OP_READ_WITH_STOP, sc->addr, 254 1.7 thorpej b, sizeof(b), NULL, 0, 0); 255 1.1 jakllsch 256 1.7 thorpej iic_release_bus(sc->tag, 0); 257 1.1 jakllsch 258 1.1 jakllsch return ret; 259 1.1 jakllsch } 260 1.2 jmcneill 261 1.5 jmcneill MODULE(MODULE_CLASS_DRIVER, mt2131, "i2cexec"); 262 1.2 jmcneill 263 1.2 jmcneill static int 264 1.2 jmcneill mt2131_modcmd(modcmd_t cmd, void *priv) 265 1.2 jmcneill { 266 1.2 jmcneill if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI) 267 1.2 jmcneill return 0; 268 1.2 jmcneill return ENOTTY; 269 1.2 jmcneill } 270