1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ccae7af2SMauro Carvalho Chehab /* 3ccae7af2SMauro Carvalho Chehab * Infineon TUA9001 silicon tuner driver 4ccae7af2SMauro Carvalho Chehab * 5ccae7af2SMauro Carvalho Chehab * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> 6ccae7af2SMauro Carvalho Chehab */ 7ccae7af2SMauro Carvalho Chehab 8ccae7af2SMauro Carvalho Chehab #include "tua9001_priv.h" 9ccae7af2SMauro Carvalho Chehab 10ccae7af2SMauro Carvalho Chehab static int tua9001_init(struct dvb_frontend *fe) 11ccae7af2SMauro Carvalho Chehab { 12465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 13465433faSAntti Palosaari struct i2c_client *client = dev->client; 14465433faSAntti Palosaari int ret, i; 15465433faSAntti Palosaari static const struct tua9001_reg_val data[] = { 16ccae7af2SMauro Carvalho Chehab {0x1e, 0x6512}, 17ccae7af2SMauro Carvalho Chehab {0x25, 0xb888}, 18ccae7af2SMauro Carvalho Chehab {0x39, 0x5460}, 19ccae7af2SMauro Carvalho Chehab {0x3b, 0x00c0}, 20ccae7af2SMauro Carvalho Chehab {0x3a, 0xf000}, 21ccae7af2SMauro Carvalho Chehab {0x08, 0x0000}, 22ccae7af2SMauro Carvalho Chehab {0x32, 0x0030}, 23ccae7af2SMauro Carvalho Chehab {0x41, 0x703a}, 24ccae7af2SMauro Carvalho Chehab {0x40, 0x1c78}, 25ccae7af2SMauro Carvalho Chehab {0x2c, 0x1c00}, 26ccae7af2SMauro Carvalho Chehab {0x36, 0xc013}, 27ccae7af2SMauro Carvalho Chehab {0x37, 0x6f18}, 28ccae7af2SMauro Carvalho Chehab {0x27, 0x0008}, 29ccae7af2SMauro Carvalho Chehab {0x2a, 0x0001}, 30ccae7af2SMauro Carvalho Chehab {0x34, 0x0a40}, 31ccae7af2SMauro Carvalho Chehab }; 32ccae7af2SMauro Carvalho Chehab 33465433faSAntti Palosaari dev_dbg(&client->dev, "\n"); 34e6211c7cSAntti Palosaari 3589054e37SAntti Palosaari if (fe->callback) { 36465433faSAntti Palosaari ret = fe->callback(client->adapter, 37465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 3889054e37SAntti Palosaari TUA9001_CMD_RESETN, 0); 39465433faSAntti Palosaari if (ret) 4089054e37SAntti Palosaari goto err; 4189054e37SAntti Palosaari } 4289054e37SAntti Palosaari 43ccae7af2SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(data); i++) { 44dd219a87SAntti Palosaari ret = regmap_write(dev->regmap, data[i].reg, data[i].val); 45465433faSAntti Palosaari if (ret) 4696676239SAntti Palosaari goto err; 47ccae7af2SMauro Carvalho Chehab } 48465433faSAntti Palosaari return 0; 4989054e37SAntti Palosaari err: 50465433faSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 5189054e37SAntti Palosaari return ret; 5289054e37SAntti Palosaari } 5389054e37SAntti Palosaari 5489054e37SAntti Palosaari static int tua9001_sleep(struct dvb_frontend *fe) 5589054e37SAntti Palosaari { 56465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 57465433faSAntti Palosaari struct i2c_client *client = dev->client; 58465433faSAntti Palosaari int ret; 5989054e37SAntti Palosaari 60465433faSAntti Palosaari dev_dbg(&client->dev, "\n"); 61e6211c7cSAntti Palosaari 62465433faSAntti Palosaari if (fe->callback) { 63465433faSAntti Palosaari ret = fe->callback(client->adapter, 64465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 6589054e37SAntti Palosaari TUA9001_CMD_RESETN, 1); 66465433faSAntti Palosaari if (ret) 67465433faSAntti Palosaari goto err; 68465433faSAntti Palosaari } 69465433faSAntti Palosaari return 0; 70465433faSAntti Palosaari err: 71465433faSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 72ccae7af2SMauro Carvalho Chehab return ret; 73ccae7af2SMauro Carvalho Chehab } 74ccae7af2SMauro Carvalho Chehab 75ccae7af2SMauro Carvalho Chehab static int tua9001_set_params(struct dvb_frontend *fe) 76ccae7af2SMauro Carvalho Chehab { 77465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 78465433faSAntti Palosaari struct i2c_client *client = dev->client; 79ccae7af2SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 80465433faSAntti Palosaari int ret, i; 81ccae7af2SMauro Carvalho Chehab u16 val; 82465433faSAntti Palosaari struct tua9001_reg_val data[2]; 83ccae7af2SMauro Carvalho Chehab 84465433faSAntti Palosaari dev_dbg(&client->dev, 85465433faSAntti Palosaari "delivery_system=%u frequency=%u bandwidth_hz=%u\n", 86e6211c7cSAntti Palosaari c->delivery_system, c->frequency, c->bandwidth_hz); 87ccae7af2SMauro Carvalho Chehab 88ccae7af2SMauro Carvalho Chehab switch (c->delivery_system) { 89ccae7af2SMauro Carvalho Chehab case SYS_DVBT: 90ccae7af2SMauro Carvalho Chehab switch (c->bandwidth_hz) { 91ccae7af2SMauro Carvalho Chehab case 8000000: 92ccae7af2SMauro Carvalho Chehab val = 0x0000; 93ccae7af2SMauro Carvalho Chehab break; 94ccae7af2SMauro Carvalho Chehab case 7000000: 95ccae7af2SMauro Carvalho Chehab val = 0x1000; 96ccae7af2SMauro Carvalho Chehab break; 97ccae7af2SMauro Carvalho Chehab case 6000000: 98ccae7af2SMauro Carvalho Chehab val = 0x2000; 99ccae7af2SMauro Carvalho Chehab break; 100ccae7af2SMauro Carvalho Chehab case 5000000: 101ccae7af2SMauro Carvalho Chehab val = 0x3000; 102ccae7af2SMauro Carvalho Chehab break; 103ccae7af2SMauro Carvalho Chehab default: 104ccae7af2SMauro Carvalho Chehab ret = -EINVAL; 105ccae7af2SMauro Carvalho Chehab goto err; 106ccae7af2SMauro Carvalho Chehab } 107ccae7af2SMauro Carvalho Chehab break; 108ccae7af2SMauro Carvalho Chehab default: 109ccae7af2SMauro Carvalho Chehab ret = -EINVAL; 110ccae7af2SMauro Carvalho Chehab goto err; 111ccae7af2SMauro Carvalho Chehab } 112ccae7af2SMauro Carvalho Chehab 113ccae7af2SMauro Carvalho Chehab data[0].reg = 0x04; 114ccae7af2SMauro Carvalho Chehab data[0].val = val; 115ccae7af2SMauro Carvalho Chehab data[1].reg = 0x1f; 11647f95dbdSAntti Palosaari data[1].val = div_u64((u64) (c->frequency - 150000000) * 48, 1000000); 117ccae7af2SMauro Carvalho Chehab 11889054e37SAntti Palosaari if (fe->callback) { 119465433faSAntti Palosaari ret = fe->callback(client->adapter, 120465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 12189054e37SAntti Palosaari TUA9001_CMD_RXEN, 0); 122465433faSAntti Palosaari if (ret) 12396676239SAntti Palosaari goto err; 12489054e37SAntti Palosaari } 12589054e37SAntti Palosaari 126ccae7af2SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(data); i++) { 127dd219a87SAntti Palosaari ret = regmap_write(dev->regmap, data[i].reg, data[i].val); 128465433faSAntti Palosaari if (ret) 12996676239SAntti Palosaari goto err; 130ccae7af2SMauro Carvalho Chehab } 131ccae7af2SMauro Carvalho Chehab 13289054e37SAntti Palosaari if (fe->callback) { 133465433faSAntti Palosaari ret = fe->callback(client->adapter, 134465433faSAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 13589054e37SAntti Palosaari TUA9001_CMD_RXEN, 1); 136465433faSAntti Palosaari if (ret) 13796676239SAntti Palosaari goto err; 13889054e37SAntti Palosaari } 139465433faSAntti Palosaari return 0; 140ccae7af2SMauro Carvalho Chehab err: 141465433faSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 142ccae7af2SMauro Carvalho Chehab return ret; 143ccae7af2SMauro Carvalho Chehab } 144ccae7af2SMauro Carvalho Chehab 145ccae7af2SMauro Carvalho Chehab static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 146ccae7af2SMauro Carvalho Chehab { 147465433faSAntti Palosaari struct tua9001_dev *dev = fe->tuner_priv; 148465433faSAntti Palosaari struct i2c_client *client = dev->client; 149e6211c7cSAntti Palosaari 150465433faSAntti Palosaari dev_dbg(&client->dev, "\n"); 151e6211c7cSAntti Palosaari 152ccae7af2SMauro Carvalho Chehab *frequency = 0; /* Zero-IF */ 153ccae7af2SMauro Carvalho Chehab return 0; 154ccae7af2SMauro Carvalho Chehab } 155ccae7af2SMauro Carvalho Chehab 156ccae7af2SMauro Carvalho Chehab static const struct dvb_tuner_ops tua9001_tuner_ops = { 157ccae7af2SMauro Carvalho Chehab .info = { 158ccae7af2SMauro Carvalho Chehab .name = "Infineon TUA9001", 159a3f90c75SMauro Carvalho Chehab .frequency_min_hz = 170 * MHz, 160a3f90c75SMauro Carvalho Chehab .frequency_max_hz = 862 * MHz, 161ccae7af2SMauro Carvalho Chehab }, 162ccae7af2SMauro Carvalho Chehab 163ccae7af2SMauro Carvalho Chehab .init = tua9001_init, 16489054e37SAntti Palosaari .sleep = tua9001_sleep, 165ccae7af2SMauro Carvalho Chehab .set_params = tua9001_set_params, 166ccae7af2SMauro Carvalho Chehab 167ccae7af2SMauro Carvalho Chehab .get_if_frequency = tua9001_get_if_frequency, 168ccae7af2SMauro Carvalho Chehab }; 169ccae7af2SMauro Carvalho Chehab 170fc851c66SAntti Palosaari static int tua9001_probe(struct i2c_client *client, 171fc851c66SAntti Palosaari const struct i2c_device_id *id) 172fc851c66SAntti Palosaari { 173465433faSAntti Palosaari struct tua9001_dev *dev; 174fc851c66SAntti Palosaari struct tua9001_platform_data *pdata = client->dev.platform_data; 175fc851c66SAntti Palosaari struct dvb_frontend *fe = pdata->dvb_frontend; 176fc851c66SAntti Palosaari int ret; 177dd219a87SAntti Palosaari static const struct regmap_config regmap_config = { 178dd219a87SAntti Palosaari .reg_bits = 8, 179dd219a87SAntti Palosaari .val_bits = 16, 180dd219a87SAntti Palosaari }; 181fc851c66SAntti Palosaari 182fc851c66SAntti Palosaari dev = kzalloc(sizeof(*dev), GFP_KERNEL); 183fc851c66SAntti Palosaari if (!dev) { 184fc851c66SAntti Palosaari ret = -ENOMEM; 185fc851c66SAntti Palosaari goto err; 186fc851c66SAntti Palosaari } 187fc851c66SAntti Palosaari 188fc851c66SAntti Palosaari dev->fe = pdata->dvb_frontend; 189dd219a87SAntti Palosaari dev->client = client; 190dd219a87SAntti Palosaari dev->regmap = devm_regmap_init_i2c(client, ®map_config); 191dd219a87SAntti Palosaari if (IS_ERR(dev->regmap)) { 192dd219a87SAntti Palosaari ret = PTR_ERR(dev->regmap); 193dd219a87SAntti Palosaari goto err_kfree; 194dd219a87SAntti Palosaari } 195fc851c66SAntti Palosaari 196fc851c66SAntti Palosaari if (fe->callback) { 197fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 198fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 199fc851c66SAntti Palosaari TUA9001_CMD_CEN, 1); 200fc851c66SAntti Palosaari if (ret) 201fc851c66SAntti Palosaari goto err_kfree; 202fc851c66SAntti Palosaari 203fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 204fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 205fc851c66SAntti Palosaari TUA9001_CMD_RXEN, 0); 206fc851c66SAntti Palosaari if (ret) 207fc851c66SAntti Palosaari goto err_kfree; 208fc851c66SAntti Palosaari 209fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 210fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 211fc851c66SAntti Palosaari TUA9001_CMD_RESETN, 1); 212fc851c66SAntti Palosaari if (ret) 213fc851c66SAntti Palosaari goto err_kfree; 214fc851c66SAntti Palosaari } 215fc851c66SAntti Palosaari 216fc851c66SAntti Palosaari fe->tuner_priv = dev; 217fc851c66SAntti Palosaari memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, 218fc851c66SAntti Palosaari sizeof(struct dvb_tuner_ops)); 219fc851c66SAntti Palosaari i2c_set_clientdata(client, dev); 220fc851c66SAntti Palosaari 221fc851c66SAntti Palosaari dev_info(&client->dev, "Infineon TUA9001 successfully attached\n"); 222fc851c66SAntti Palosaari return 0; 223fc851c66SAntti Palosaari err_kfree: 224fc851c66SAntti Palosaari kfree(dev); 225fc851c66SAntti Palosaari err: 226fc851c66SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 227fc851c66SAntti Palosaari return ret; 228fc851c66SAntti Palosaari } 229fc851c66SAntti Palosaari 230*ed5c2f5fSUwe Kleine-König static void tua9001_remove(struct i2c_client *client) 231fc851c66SAntti Palosaari { 232465433faSAntti Palosaari struct tua9001_dev *dev = i2c_get_clientdata(client); 233fc851c66SAntti Palosaari struct dvb_frontend *fe = dev->fe; 234fc851c66SAntti Palosaari int ret; 235fc851c66SAntti Palosaari 236fc851c66SAntti Palosaari dev_dbg(&client->dev, "\n"); 237fc851c66SAntti Palosaari 238fc851c66SAntti Palosaari if (fe->callback) { 239fc851c66SAntti Palosaari ret = fe->callback(client->adapter, 240fc851c66SAntti Palosaari DVB_FRONTEND_COMPONENT_TUNER, 241fc851c66SAntti Palosaari TUA9001_CMD_CEN, 0); 242fc851c66SAntti Palosaari if (ret) 24348f45c2aSUwe Kleine-König dev_err(&client->dev, "Tuner disable failed (%pe)\n", ERR_PTR(ret)); 244fc851c66SAntti Palosaari } 245fc851c66SAntti Palosaari kfree(dev); 246fc851c66SAntti Palosaari } 247fc851c66SAntti Palosaari 248fc851c66SAntti Palosaari static const struct i2c_device_id tua9001_id_table[] = { 249fc851c66SAntti Palosaari {"tua9001", 0}, 250fc851c66SAntti Palosaari {} 251fc851c66SAntti Palosaari }; 252fc851c66SAntti Palosaari MODULE_DEVICE_TABLE(i2c, tua9001_id_table); 253fc851c66SAntti Palosaari 254fc851c66SAntti Palosaari static struct i2c_driver tua9001_driver = { 255fc851c66SAntti Palosaari .driver = { 256fc851c66SAntti Palosaari .name = "tua9001", 257fc851c66SAntti Palosaari .suppress_bind_attrs = true, 258fc851c66SAntti Palosaari }, 259fc851c66SAntti Palosaari .probe = tua9001_probe, 260fc851c66SAntti Palosaari .remove = tua9001_remove, 261fc851c66SAntti Palosaari .id_table = tua9001_id_table, 262fc851c66SAntti Palosaari }; 263fc851c66SAntti Palosaari 264fc851c66SAntti Palosaari module_i2c_driver(tua9001_driver); 265fc851c66SAntti Palosaari 266ccae7af2SMauro Carvalho Chehab MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver"); 267ccae7af2SMauro Carvalho Chehab MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 268ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 269