1ccae7af2SMauro Carvalho Chehab /* 2ccae7af2SMauro Carvalho Chehab * Infineon TUA9001 silicon tuner driver 3ccae7af2SMauro Carvalho Chehab * 4ccae7af2SMauro Carvalho Chehab * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> 5ccae7af2SMauro Carvalho Chehab * 6ccae7af2SMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 7ccae7af2SMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 8ccae7af2SMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 9ccae7af2SMauro Carvalho Chehab * (at your option) any later version. 10ccae7af2SMauro Carvalho Chehab * 11ccae7af2SMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 12ccae7af2SMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 13ccae7af2SMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14ccae7af2SMauro Carvalho Chehab * GNU General Public License for more details. 15ccae7af2SMauro Carvalho Chehab */ 16ccae7af2SMauro Carvalho Chehab 17ccae7af2SMauro Carvalho Chehab #include "tua9001_priv.h" 18ccae7af2SMauro Carvalho Chehab 19ccae7af2SMauro Carvalho Chehab static int tua9001_init(struct dvb_frontend *fe) 20ccae7af2SMauro Carvalho Chehab { 21465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 22465433faSAntti Palosaari struct i2c_client *client = dev->client; 23465433faSAntti Palosaari int ret, i; 24465433faSAntti Palosaari static const struct tua9001_reg_val data[] = { 25ccae7af2SMauro Carvalho Chehab {0x1e, 0x6512}, 26ccae7af2SMauro Carvalho Chehab {0x25, 0xb888}, 27ccae7af2SMauro Carvalho Chehab {0x39, 0x5460}, 28ccae7af2SMauro Carvalho Chehab {0x3b, 0x00c0}, 29ccae7af2SMauro Carvalho Chehab {0x3a, 0xf000}, 30ccae7af2SMauro Carvalho Chehab {0x08, 0x0000}, 31ccae7af2SMauro Carvalho Chehab {0x32, 0x0030}, 32ccae7af2SMauro Carvalho Chehab {0x41, 0x703a}, 33ccae7af2SMauro Carvalho Chehab {0x40, 0x1c78}, 34ccae7af2SMauro Carvalho Chehab {0x2c, 0x1c00}, 35ccae7af2SMauro Carvalho Chehab {0x36, 0xc013}, 36ccae7af2SMauro Carvalho Chehab {0x37, 0x6f18}, 37ccae7af2SMauro Carvalho Chehab {0x27, 0x0008}, 38ccae7af2SMauro Carvalho Chehab {0x2a, 0x0001}, 39ccae7af2SMauro Carvalho Chehab {0x34, 0x0a40}, 40ccae7af2SMauro Carvalho Chehab }; 41ccae7af2SMauro Carvalho Chehab 42465433faSAntti Palosaari dev_dbg(&client->dev, "\n"); 43e6211c7cSAntti Palosaari 4489054e37SAntti Palosaari if (fe->callback) { 45465433faSAntti Palosaari ret = fe->callback(client->adapter, 46465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 4789054e37SAntti Palosaari TUA9001_CMD_RESETN, 0); 48465433faSAntti Palosaari if (ret) 4989054e37SAntti Palosaari goto err; 5089054e37SAntti Palosaari } 5189054e37SAntti Palosaari 52ccae7af2SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(data); i++) { 53dd219a87SAntti Palosaari ret = regmap_write(dev->regmap, data[i].reg, data[i].val); 54465433faSAntti Palosaari if (ret) 5596676239SAntti Palosaari goto err; 56ccae7af2SMauro Carvalho Chehab } 57465433faSAntti Palosaari return 0; 5889054e37SAntti Palosaari err: 59465433faSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 6089054e37SAntti Palosaari return ret; 6189054e37SAntti Palosaari } 6289054e37SAntti Palosaari 6389054e37SAntti Palosaari static int tua9001_sleep(struct dvb_frontend *fe) 6489054e37SAntti Palosaari { 65465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 66465433faSAntti Palosaari struct i2c_client *client = dev->client; 67465433faSAntti Palosaari int ret; 6889054e37SAntti Palosaari 69465433faSAntti Palosaari dev_dbg(&client->dev, "\n"); 70e6211c7cSAntti Palosaari 71465433faSAntti Palosaari if (fe->callback) { 72465433faSAntti Palosaari ret = fe->callback(client->adapter, 73465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 7489054e37SAntti Palosaari TUA9001_CMD_RESETN, 1); 75465433faSAntti Palosaari if (ret) 76465433faSAntti Palosaari goto err; 77465433faSAntti Palosaari } 78465433faSAntti Palosaari return 0; 79465433faSAntti Palosaari err: 80465433faSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 81ccae7af2SMauro Carvalho Chehab return ret; 82ccae7af2SMauro Carvalho Chehab } 83ccae7af2SMauro Carvalho Chehab 84ccae7af2SMauro Carvalho Chehab static int tua9001_set_params(struct dvb_frontend *fe) 85ccae7af2SMauro Carvalho Chehab { 86465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 87465433faSAntti Palosaari struct i2c_client *client = dev->client; 88ccae7af2SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 89465433faSAntti Palosaari int ret, i; 90ccae7af2SMauro Carvalho Chehab u16 val; 91465433faSAntti Palosaari struct tua9001_reg_val data[2]; 92ccae7af2SMauro Carvalho Chehab 93465433faSAntti Palosaari dev_dbg(&client->dev, 94465433faSAntti Palosaari "delivery_system=%u frequency=%u bandwidth_hz=%u\n", 95e6211c7cSAntti Palosaari c->delivery_system, c->frequency, c->bandwidth_hz); 96ccae7af2SMauro Carvalho Chehab 97ccae7af2SMauro Carvalho Chehab switch (c->delivery_system) { 98ccae7af2SMauro Carvalho Chehab case SYS_DVBT: 99ccae7af2SMauro Carvalho Chehab switch (c->bandwidth_hz) { 100ccae7af2SMauro Carvalho Chehab case 8000000: 101ccae7af2SMauro Carvalho Chehab val = 0x0000; 102ccae7af2SMauro Carvalho Chehab break; 103ccae7af2SMauro Carvalho Chehab case 7000000: 104ccae7af2SMauro Carvalho Chehab val = 0x1000; 105ccae7af2SMauro Carvalho Chehab break; 106ccae7af2SMauro Carvalho Chehab case 6000000: 107ccae7af2SMauro Carvalho Chehab val = 0x2000; 108ccae7af2SMauro Carvalho Chehab break; 109ccae7af2SMauro Carvalho Chehab case 5000000: 110ccae7af2SMauro Carvalho Chehab val = 0x3000; 111ccae7af2SMauro Carvalho Chehab break; 112ccae7af2SMauro Carvalho Chehab default: 113ccae7af2SMauro Carvalho Chehab ret = -EINVAL; 114ccae7af2SMauro Carvalho Chehab goto err; 115ccae7af2SMauro Carvalho Chehab } 116ccae7af2SMauro Carvalho Chehab break; 117ccae7af2SMauro Carvalho Chehab default: 118ccae7af2SMauro Carvalho Chehab ret = -EINVAL; 119ccae7af2SMauro Carvalho Chehab goto err; 120ccae7af2SMauro Carvalho Chehab } 121ccae7af2SMauro Carvalho Chehab 122ccae7af2SMauro Carvalho Chehab data[0].reg = 0x04; 123ccae7af2SMauro Carvalho Chehab data[0].val = val; 124ccae7af2SMauro Carvalho Chehab data[1].reg = 0x1f; 12547f95dbdSAntti Palosaari data[1].val = div_u64((u64) (c->frequency - 150000000) * 48, 1000000); 126ccae7af2SMauro Carvalho Chehab 12789054e37SAntti Palosaari if (fe->callback) { 128465433faSAntti Palosaari ret = fe->callback(client->adapter, 129465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 13089054e37SAntti Palosaari TUA9001_CMD_RXEN, 0); 131465433faSAntti Palosaari if (ret) 13296676239SAntti Palosaari goto err; 13389054e37SAntti Palosaari } 13489054e37SAntti Palosaari 135ccae7af2SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(data); i++) { 136dd219a87SAntti Palosaari ret = regmap_write(dev->regmap, data[i].reg, data[i].val); 137465433faSAntti Palosaari if (ret) 13896676239SAntti Palosaari goto err; 139ccae7af2SMauro Carvalho Chehab } 140ccae7af2SMauro Carvalho Chehab 14189054e37SAntti Palosaari if (fe->callback) { 142465433faSAntti Palosaari ret = fe->callback(client->adapter, 143465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 14489054e37SAntti Palosaari TUA9001_CMD_RXEN, 1); 145465433faSAntti Palosaari if (ret) 14696676239SAntti Palosaari goto err; 14789054e37SAntti Palosaari } 148465433faSAntti Palosaari return 0; 149ccae7af2SMauro Carvalho Chehab err: 150465433faSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 151ccae7af2SMauro Carvalho Chehab return ret; 152ccae7af2SMauro Carvalho Chehab } 153ccae7af2SMauro Carvalho Chehab 154ccae7af2SMauro Carvalho Chehab static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 155ccae7af2SMauro Carvalho Chehab { 156465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 157465433faSAntti Palosaari struct i2c_client *client = dev->client; 158e6211c7cSAntti Palosaari 159465433faSAntti Palosaari dev_dbg(&client->dev, "\n"); 160e6211c7cSAntti Palosaari 161ccae7af2SMauro Carvalho Chehab *frequency = 0; /* Zero-IF */ 162ccae7af2SMauro Carvalho Chehab return 0; 163ccae7af2SMauro Carvalho Chehab } 164ccae7af2SMauro Carvalho Chehab 165ccae7af2SMauro Carvalho Chehab static const struct dvb_tuner_ops tua9001_tuner_ops = { 166ccae7af2SMauro Carvalho Chehab .info = { 167ccae7af2SMauro Carvalho Chehab .name = "Infineon TUA9001", 168*a3f90c75SMauro Carvalho Chehab .frequency_min_hz = 170 * MHz, 169*a3f90c75SMauro Carvalho Chehab .frequency_max_hz = 862 * MHz, 170ccae7af2SMauro Carvalho Chehab }, 171ccae7af2SMauro Carvalho Chehab 172ccae7af2SMauro Carvalho Chehab .init = tua9001_init, 17389054e37SAntti Palosaari .sleep = tua9001_sleep, 174ccae7af2SMauro Carvalho Chehab .set_params = tua9001_set_params, 175ccae7af2SMauro Carvalho Chehab 176ccae7af2SMauro Carvalho Chehab .get_if_frequency = tua9001_get_if_frequency, 177ccae7af2SMauro Carvalho Chehab }; 178ccae7af2SMauro Carvalho Chehab 179fc851c66SAntti Palosaari static int tua9001_probe(struct i2c_client *client, 180fc851c66SAntti Palosaari const struct i2c_device_id *id) 181fc851c66SAntti Palosaari { 182465433faSAntti Palosaari struct tua9001_dev *dev; 183fc851c66SAntti Palosaari struct tua9001_platform_data *pdata = client->dev.platform_data; 184fc851c66SAntti Palosaari struct dvb_frontend *fe = pdata->dvb_frontend; 185fc851c66SAntti Palosaari int ret; 186dd219a87SAntti Palosaari static const struct regmap_config regmap_config = { 187dd219a87SAntti Palosaari .reg_bits = 8, 188dd219a87SAntti Palosaari .val_bits = 16, 189dd219a87SAntti Palosaari }; 190fc851c66SAntti Palosaari 191fc851c66SAntti Palosaari dev = kzalloc(sizeof(*dev), GFP_KERNEL); 192fc851c66SAntti Palosaari if (!dev) { 193fc851c66SAntti Palosaari ret = -ENOMEM; 194fc851c66SAntti Palosaari goto err; 195fc851c66SAntti Palosaari } 196fc851c66SAntti Palosaari 197fc851c66SAntti Palosaari dev->fe = pdata->dvb_frontend; 198dd219a87SAntti Palosaari dev->client = client; 199dd219a87SAntti Palosaari dev->regmap = devm_regmap_init_i2c(client, ®map_config); 200dd219a87SAntti Palosaari if (IS_ERR(dev->regmap)) { 201dd219a87SAntti Palosaari ret = PTR_ERR(dev->regmap); 202dd219a87SAntti Palosaari goto err_kfree; 203dd219a87SAntti Palosaari } 204fc851c66SAntti Palosaari 205fc851c66SAntti Palosaari if (fe->callback) { 206fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 207fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 208fc851c66SAntti Palosaari TUA9001_CMD_CEN, 1); 209fc851c66SAntti Palosaari if (ret) 210fc851c66SAntti Palosaari goto err_kfree; 211fc851c66SAntti Palosaari 212fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 213fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 214fc851c66SAntti Palosaari TUA9001_CMD_RXEN, 0); 215fc851c66SAntti Palosaari if (ret) 216fc851c66SAntti Palosaari goto err_kfree; 217fc851c66SAntti Palosaari 218fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 219fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 220fc851c66SAntti Palosaari TUA9001_CMD_RESETN, 1); 221fc851c66SAntti Palosaari if (ret) 222fc851c66SAntti Palosaari goto err_kfree; 223fc851c66SAntti Palosaari } 224fc851c66SAntti Palosaari 225fc851c66SAntti Palosaari fe->tuner_priv = dev; 226fc851c66SAntti Palosaari memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, 227fc851c66SAntti Palosaari sizeof(struct dvb_tuner_ops)); 228fc851c66SAntti Palosaari i2c_set_clientdata(client, dev); 229fc851c66SAntti Palosaari 230fc851c66SAntti Palosaari dev_info(&client->dev, "Infineon TUA9001 successfully attached\n"); 231fc851c66SAntti Palosaari return 0; 232fc851c66SAntti Palosaari err_kfree: 233fc851c66SAntti Palosaari kfree(dev); 234fc851c66SAntti Palosaari err: 235fc851c66SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 236fc851c66SAntti Palosaari return ret; 237fc851c66SAntti Palosaari } 238fc851c66SAntti Palosaari 239fc851c66SAntti Palosaari static int tua9001_remove(struct i2c_client *client) 240fc851c66SAntti Palosaari { 241465433faSAntti Palosaari struct tua9001_dev *dev = i2c_get_clientdata(client); 242fc851c66SAntti Palosaari struct dvb_frontend *fe = dev->fe; 243fc851c66SAntti Palosaari int ret; 244fc851c66SAntti Palosaari 245fc851c66SAntti Palosaari dev_dbg(&client->dev, "\n"); 246fc851c66SAntti Palosaari 247fc851c66SAntti Palosaari if (fe->callback) { 248fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 249fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 250fc851c66SAntti Palosaari TUA9001_CMD_CEN, 0); 251fc851c66SAntti Palosaari if (ret) 252fc851c66SAntti Palosaari goto err_kfree; 253fc851c66SAntti Palosaari } 254fc851c66SAntti Palosaari kfree(dev); 255fc851c66SAntti Palosaari return 0; 256fc851c66SAntti Palosaari err_kfree: 257fc851c66SAntti Palosaari kfree(dev); 258fc851c66SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 259fc851c66SAntti Palosaari return ret; 260fc851c66SAntti Palosaari } 261fc851c66SAntti Palosaari 262fc851c66SAntti Palosaari static const struct i2c_device_id tua9001_id_table[] = { 263fc851c66SAntti Palosaari {"tua9001", 0}, 264fc851c66SAntti Palosaari {} 265fc851c66SAntti Palosaari }; 266fc851c66SAntti Palosaari MODULE_DEVICE_TABLE(i2c, tua9001_id_table); 267fc851c66SAntti Palosaari 268fc851c66SAntti Palosaari static struct i2c_driver tua9001_driver = { 269fc851c66SAntti Palosaari .driver = { 270fc851c66SAntti Palosaari .name = "tua9001", 271fc851c66SAntti Palosaari .suppress_bind_attrs = true, 272fc851c66SAntti Palosaari }, 273fc851c66SAntti Palosaari .probe = tua9001_probe, 274fc851c66SAntti Palosaari .remove = tua9001_remove, 275fc851c66SAntti Palosaari .id_table = tua9001_id_table, 276fc851c66SAntti Palosaari }; 277fc851c66SAntti Palosaari 278fc851c66SAntti Palosaari module_i2c_driver(tua9001_driver); 279fc851c66SAntti Palosaari 280ccae7af2SMauro Carvalho Chehab MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver"); 281ccae7af2SMauro Carvalho Chehab MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 282ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 283