18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Infineon TUA9001 silicon tuner driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "tua9001_priv.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic int tua9001_init(struct dvb_frontend *fe) 118c2ecf20Sopenharmony_ci{ 128c2ecf20Sopenharmony_ci struct tua9001_dev *dev = fe->tuner_priv; 138c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 148c2ecf20Sopenharmony_ci int ret, i; 158c2ecf20Sopenharmony_ci static const struct tua9001_reg_val data[] = { 168c2ecf20Sopenharmony_ci {0x1e, 0x6512}, 178c2ecf20Sopenharmony_ci {0x25, 0xb888}, 188c2ecf20Sopenharmony_ci {0x39, 0x5460}, 198c2ecf20Sopenharmony_ci {0x3b, 0x00c0}, 208c2ecf20Sopenharmony_ci {0x3a, 0xf000}, 218c2ecf20Sopenharmony_ci {0x08, 0x0000}, 228c2ecf20Sopenharmony_ci {0x32, 0x0030}, 238c2ecf20Sopenharmony_ci {0x41, 0x703a}, 248c2ecf20Sopenharmony_ci {0x40, 0x1c78}, 258c2ecf20Sopenharmony_ci {0x2c, 0x1c00}, 268c2ecf20Sopenharmony_ci {0x36, 0xc013}, 278c2ecf20Sopenharmony_ci {0x37, 0x6f18}, 288c2ecf20Sopenharmony_ci {0x27, 0x0008}, 298c2ecf20Sopenharmony_ci {0x2a, 0x0001}, 308c2ecf20Sopenharmony_ci {0x34, 0x0a40}, 318c2ecf20Sopenharmony_ci }; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (fe->callback) { 368c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 378c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 388c2ecf20Sopenharmony_ci TUA9001_CMD_RESETN, 0); 398c2ecf20Sopenharmony_ci if (ret) 408c2ecf20Sopenharmony_ci goto err; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data); i++) { 448c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, data[i].reg, data[i].val); 458c2ecf20Sopenharmony_ci if (ret) 468c2ecf20Sopenharmony_ci goto err; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci return 0; 498c2ecf20Sopenharmony_cierr: 508c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 518c2ecf20Sopenharmony_ci return ret; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int tua9001_sleep(struct dvb_frontend *fe) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct tua9001_dev *dev = fe->tuner_priv; 578c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 588c2ecf20Sopenharmony_ci int ret; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (fe->callback) { 638c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 648c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 658c2ecf20Sopenharmony_ci TUA9001_CMD_RESETN, 1); 668c2ecf20Sopenharmony_ci if (ret) 678c2ecf20Sopenharmony_ci goto err; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_cierr: 718c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int tua9001_set_params(struct dvb_frontend *fe) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct tua9001_dev *dev = fe->tuner_priv; 788c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 798c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 808c2ecf20Sopenharmony_ci int ret, i; 818c2ecf20Sopenharmony_ci u16 val; 828c2ecf20Sopenharmony_ci struct tua9001_reg_val data[2]; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci dev_dbg(&client->dev, 858c2ecf20Sopenharmony_ci "delivery_system=%u frequency=%u bandwidth_hz=%u\n", 868c2ecf20Sopenharmony_ci c->delivery_system, c->frequency, c->bandwidth_hz); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci switch (c->delivery_system) { 898c2ecf20Sopenharmony_ci case SYS_DVBT: 908c2ecf20Sopenharmony_ci switch (c->bandwidth_hz) { 918c2ecf20Sopenharmony_ci case 8000000: 928c2ecf20Sopenharmony_ci val = 0x0000; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci case 7000000: 958c2ecf20Sopenharmony_ci val = 0x1000; 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci case 6000000: 988c2ecf20Sopenharmony_ci val = 0x2000; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case 5000000: 1018c2ecf20Sopenharmony_ci val = 0x3000; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci default: 1048c2ecf20Sopenharmony_ci ret = -EINVAL; 1058c2ecf20Sopenharmony_ci goto err; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci default: 1098c2ecf20Sopenharmony_ci ret = -EINVAL; 1108c2ecf20Sopenharmony_ci goto err; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci data[0].reg = 0x04; 1148c2ecf20Sopenharmony_ci data[0].val = val; 1158c2ecf20Sopenharmony_ci data[1].reg = 0x1f; 1168c2ecf20Sopenharmony_ci data[1].val = div_u64((u64) (c->frequency - 150000000) * 48, 1000000); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (fe->callback) { 1198c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 1208c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 1218c2ecf20Sopenharmony_ci TUA9001_CMD_RXEN, 0); 1228c2ecf20Sopenharmony_ci if (ret) 1238c2ecf20Sopenharmony_ci goto err; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data); i++) { 1278c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, data[i].reg, data[i].val); 1288c2ecf20Sopenharmony_ci if (ret) 1298c2ecf20Sopenharmony_ci goto err; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (fe->callback) { 1338c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 1348c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 1358c2ecf20Sopenharmony_ci TUA9001_CMD_RXEN, 1); 1368c2ecf20Sopenharmony_ci if (ret) 1378c2ecf20Sopenharmony_ci goto err; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_cierr: 1418c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 1428c2ecf20Sopenharmony_ci return ret; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct tua9001_dev *dev = fe->tuner_priv; 1488c2ecf20Sopenharmony_ci struct i2c_client *client = dev->client; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci *frequency = 0; /* Zero-IF */ 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops tua9001_tuner_ops = { 1578c2ecf20Sopenharmony_ci .info = { 1588c2ecf20Sopenharmony_ci .name = "Infineon TUA9001", 1598c2ecf20Sopenharmony_ci .frequency_min_hz = 170 * MHz, 1608c2ecf20Sopenharmony_ci .frequency_max_hz = 862 * MHz, 1618c2ecf20Sopenharmony_ci }, 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci .init = tua9001_init, 1648c2ecf20Sopenharmony_ci .sleep = tua9001_sleep, 1658c2ecf20Sopenharmony_ci .set_params = tua9001_set_params, 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci .get_if_frequency = tua9001_get_if_frequency, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int tua9001_probe(struct i2c_client *client, 1718c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct tua9001_dev *dev; 1748c2ecf20Sopenharmony_ci struct tua9001_platform_data *pdata = client->dev.platform_data; 1758c2ecf20Sopenharmony_ci struct dvb_frontend *fe = pdata->dvb_frontend; 1768c2ecf20Sopenharmony_ci int ret; 1778c2ecf20Sopenharmony_ci static const struct regmap_config regmap_config = { 1788c2ecf20Sopenharmony_ci .reg_bits = 8, 1798c2ecf20Sopenharmony_ci .val_bits = 16, 1808c2ecf20Sopenharmony_ci }; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1838c2ecf20Sopenharmony_ci if (!dev) { 1848c2ecf20Sopenharmony_ci ret = -ENOMEM; 1858c2ecf20Sopenharmony_ci goto err; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci dev->fe = pdata->dvb_frontend; 1898c2ecf20Sopenharmony_ci dev->client = client; 1908c2ecf20Sopenharmony_ci dev->regmap = devm_regmap_init_i2c(client, ®map_config); 1918c2ecf20Sopenharmony_ci if (IS_ERR(dev->regmap)) { 1928c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->regmap); 1938c2ecf20Sopenharmony_ci goto err_kfree; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (fe->callback) { 1978c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 1988c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 1998c2ecf20Sopenharmony_ci TUA9001_CMD_CEN, 1); 2008c2ecf20Sopenharmony_ci if (ret) 2018c2ecf20Sopenharmony_ci goto err_kfree; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 2048c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 2058c2ecf20Sopenharmony_ci TUA9001_CMD_RXEN, 0); 2068c2ecf20Sopenharmony_ci if (ret) 2078c2ecf20Sopenharmony_ci goto err_kfree; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 2108c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 2118c2ecf20Sopenharmony_ci TUA9001_CMD_RESETN, 1); 2128c2ecf20Sopenharmony_ci if (ret) 2138c2ecf20Sopenharmony_ci goto err_kfree; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci fe->tuner_priv = dev; 2178c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, 2188c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 2198c2ecf20Sopenharmony_ci i2c_set_clientdata(client, dev); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci dev_info(&client->dev, "Infineon TUA9001 successfully attached\n"); 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_cierr_kfree: 2248c2ecf20Sopenharmony_ci kfree(dev); 2258c2ecf20Sopenharmony_cierr: 2268c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int tua9001_remove(struct i2c_client *client) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct tua9001_dev *dev = i2c_get_clientdata(client); 2338c2ecf20Sopenharmony_ci struct dvb_frontend *fe = dev->fe; 2348c2ecf20Sopenharmony_ci int ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "\n"); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (fe->callback) { 2398c2ecf20Sopenharmony_ci ret = fe->callback(client->adapter, 2408c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 2418c2ecf20Sopenharmony_ci TUA9001_CMD_CEN, 0); 2428c2ecf20Sopenharmony_ci if (ret) 2438c2ecf20Sopenharmony_ci goto err_kfree; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci kfree(dev); 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_cierr_kfree: 2488c2ecf20Sopenharmony_ci kfree(dev); 2498c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic const struct i2c_device_id tua9001_id_table[] = { 2548c2ecf20Sopenharmony_ci {"tua9001", 0}, 2558c2ecf20Sopenharmony_ci {} 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tua9001_id_table); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic struct i2c_driver tua9001_driver = { 2608c2ecf20Sopenharmony_ci .driver = { 2618c2ecf20Sopenharmony_ci .name = "tua9001", 2628c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 2638c2ecf20Sopenharmony_ci }, 2648c2ecf20Sopenharmony_ci .probe = tua9001_probe, 2658c2ecf20Sopenharmony_ci .remove = tua9001_remove, 2668c2ecf20Sopenharmony_ci .id_table = tua9001_id_table, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cimodule_i2c_driver(tua9001_driver); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver"); 2728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 2738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 274