268 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Infineon TUA9001 silicon tuner driver4 *5 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>6 */7 8#include "tua9001_priv.h"9 10static int tua9001_init(struct dvb_frontend *fe)11{12 struct tua9001_dev *dev = fe->tuner_priv;13 struct i2c_client *client = dev->client;14 int ret, i;15 static const struct tua9001_reg_val data[] = {16 {0x1e, 0x6512},17 {0x25, 0xb888},18 {0x39, 0x5460},19 {0x3b, 0x00c0},20 {0x3a, 0xf000},21 {0x08, 0x0000},22 {0x32, 0x0030},23 {0x41, 0x703a},24 {0x40, 0x1c78},25 {0x2c, 0x1c00},26 {0x36, 0xc013},27 {0x37, 0x6f18},28 {0x27, 0x0008},29 {0x2a, 0x0001},30 {0x34, 0x0a40},31 };32 33 dev_dbg(&client->dev, "\n");34 35 if (fe->callback) {36 ret = fe->callback(client->adapter,37 DVB_FRONTEND_COMPONENT_TUNER,38 TUA9001_CMD_RESETN, 0);39 if (ret)40 goto err;41 }42 43 for (i = 0; i < ARRAY_SIZE(data); i++) {44 ret = regmap_write(dev->regmap, data[i].reg, data[i].val);45 if (ret)46 goto err;47 }48 return 0;49err:50 dev_dbg(&client->dev, "failed=%d\n", ret);51 return ret;52}53 54static int tua9001_sleep(struct dvb_frontend *fe)55{56 struct tua9001_dev *dev = fe->tuner_priv;57 struct i2c_client *client = dev->client;58 int ret;59 60 dev_dbg(&client->dev, "\n");61 62 if (fe->callback) {63 ret = fe->callback(client->adapter,64 DVB_FRONTEND_COMPONENT_TUNER,65 TUA9001_CMD_RESETN, 1);66 if (ret)67 goto err;68 }69 return 0;70err:71 dev_dbg(&client->dev, "failed=%d\n", ret);72 return ret;73}74 75static int tua9001_set_params(struct dvb_frontend *fe)76{77 struct tua9001_dev *dev = fe->tuner_priv;78 struct i2c_client *client = dev->client;79 struct dtv_frontend_properties *c = &fe->dtv_property_cache;80 int ret, i;81 u16 val;82 struct tua9001_reg_val data[2];83 84 dev_dbg(&client->dev,85 "delivery_system=%u frequency=%u bandwidth_hz=%u\n",86 c->delivery_system, c->frequency, c->bandwidth_hz);87 88 switch (c->delivery_system) {89 case SYS_DVBT:90 switch (c->bandwidth_hz) {91 case 8000000:92 val = 0x0000;93 break;94 case 7000000:95 val = 0x1000;96 break;97 case 6000000:98 val = 0x2000;99 break;100 case 5000000:101 val = 0x3000;102 break;103 default:104 ret = -EINVAL;105 goto err;106 }107 break;108 default:109 ret = -EINVAL;110 goto err;111 }112 113 data[0].reg = 0x04;114 data[0].val = val;115 data[1].reg = 0x1f;116 data[1].val = div_u64((u64) (c->frequency - 150000000) * 48, 1000000);117 118 if (fe->callback) {119 ret = fe->callback(client->adapter,120 DVB_FRONTEND_COMPONENT_TUNER,121 TUA9001_CMD_RXEN, 0);122 if (ret)123 goto err;124 }125 126 for (i = 0; i < ARRAY_SIZE(data); i++) {127 ret = regmap_write(dev->regmap, data[i].reg, data[i].val);128 if (ret)129 goto err;130 }131 132 if (fe->callback) {133 ret = fe->callback(client->adapter,134 DVB_FRONTEND_COMPONENT_TUNER,135 TUA9001_CMD_RXEN, 1);136 if (ret)137 goto err;138 }139 return 0;140err:141 dev_dbg(&client->dev, "failed=%d\n", ret);142 return ret;143}144 145static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)146{147 struct tua9001_dev *dev = fe->tuner_priv;148 struct i2c_client *client = dev->client;149 150 dev_dbg(&client->dev, "\n");151 152 *frequency = 0; /* Zero-IF */153 return 0;154}155 156static const struct dvb_tuner_ops tua9001_tuner_ops = {157 .info = {158 .name = "Infineon TUA9001",159 .frequency_min_hz = 170 * MHz,160 .frequency_max_hz = 862 * MHz,161 },162 163 .init = tua9001_init,164 .sleep = tua9001_sleep,165 .set_params = tua9001_set_params,166 167 .get_if_frequency = tua9001_get_if_frequency,168};169 170static int tua9001_probe(struct i2c_client *client)171{172 struct tua9001_dev *dev;173 struct tua9001_platform_data *pdata = client->dev.platform_data;174 struct dvb_frontend *fe = pdata->dvb_frontend;175 int ret;176 static const struct regmap_config regmap_config = {177 .reg_bits = 8,178 .val_bits = 16,179 };180 181 dev = kzalloc(sizeof(*dev), GFP_KERNEL);182 if (!dev) {183 ret = -ENOMEM;184 goto err;185 }186 187 dev->fe = pdata->dvb_frontend;188 dev->client = client;189 dev->regmap = devm_regmap_init_i2c(client, ®map_config);190 if (IS_ERR(dev->regmap)) {191 ret = PTR_ERR(dev->regmap);192 goto err_kfree;193 }194 195 if (fe->callback) {196 ret = fe->callback(client->adapter,197 DVB_FRONTEND_COMPONENT_TUNER,198 TUA9001_CMD_CEN, 1);199 if (ret)200 goto err_kfree;201 202 ret = fe->callback(client->adapter,203 DVB_FRONTEND_COMPONENT_TUNER,204 TUA9001_CMD_RXEN, 0);205 if (ret)206 goto err_kfree;207 208 ret = fe->callback(client->adapter,209 DVB_FRONTEND_COMPONENT_TUNER,210 TUA9001_CMD_RESETN, 1);211 if (ret)212 goto err_kfree;213 }214 215 fe->tuner_priv = dev;216 memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,217 sizeof(struct dvb_tuner_ops));218 i2c_set_clientdata(client, dev);219 220 dev_info(&client->dev, "Infineon TUA9001 successfully attached\n");221 return 0;222err_kfree:223 kfree(dev);224err:225 dev_dbg(&client->dev, "failed=%d\n", ret);226 return ret;227}228 229static void tua9001_remove(struct i2c_client *client)230{231 struct tua9001_dev *dev = i2c_get_clientdata(client);232 struct dvb_frontend *fe = dev->fe;233 int ret;234 235 dev_dbg(&client->dev, "\n");236 237 if (fe->callback) {238 ret = fe->callback(client->adapter,239 DVB_FRONTEND_COMPONENT_TUNER,240 TUA9001_CMD_CEN, 0);241 if (ret)242 dev_err(&client->dev, "Tuner disable failed (%pe)\n", ERR_PTR(ret));243 }244 kfree(dev);245}246 247static const struct i2c_device_id tua9001_id_table[] = {248 { "tua9001" },249 {}250};251MODULE_DEVICE_TABLE(i2c, tua9001_id_table);252 253static struct i2c_driver tua9001_driver = {254 .driver = {255 .name = "tua9001",256 .suppress_bind_attrs = true,257 },258 .probe = tua9001_probe,259 .remove = tua9001_remove,260 .id_table = tua9001_id_table,261};262 263module_i2c_driver(tua9001_driver);264 265MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver");266MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");267MODULE_LICENSE("GPL");268