1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Infineon TUA9001 silicon tuner driver 4 * 5 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> 6 */ 7 8 #include "tua9001_priv.h" 9 10 static 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; 49 err: 50 dev_dbg(&client->dev, "failed=%d\n", ret); 51 return ret; 52 } 53 54 static 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; 70 err: 71 dev_dbg(&client->dev, "failed=%d\n", ret); 72 return ret; 73 } 74 75 static 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; 140 err: 141 dev_dbg(&client->dev, "failed=%d\n", ret); 142 return ret; 143 } 144 145 static 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 156 static 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 170 static int tua9001_probe(struct i2c_client *client, 171 const struct i2c_device_id *id) 172 { 173 struct tua9001_dev *dev; 174 struct tua9001_platform_data *pdata = client->dev.platform_data; 175 struct dvb_frontend *fe = pdata->dvb_frontend; 176 int ret; 177 static const struct regmap_config regmap_config = { 178 .reg_bits = 8, 179 .val_bits = 16, 180 }; 181 182 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 183 if (!dev) { 184 ret = -ENOMEM; 185 goto err; 186 } 187 188 dev->fe = pdata->dvb_frontend; 189 dev->client = client; 190 dev->regmap = devm_regmap_init_i2c(client, ®map_config); 191 if (IS_ERR(dev->regmap)) { 192 ret = PTR_ERR(dev->regmap); 193 goto err_kfree; 194 } 195 196 if (fe->callback) { 197 ret = fe->callback(client->adapter, 198 DVB_FRONTEND_COMPONENT_TUNER, 199 TUA9001_CMD_CEN, 1); 200 if (ret) 201 goto err_kfree; 202 203 ret = fe->callback(client->adapter, 204 DVB_FRONTEND_COMPONENT_TUNER, 205 TUA9001_CMD_RXEN, 0); 206 if (ret) 207 goto err_kfree; 208 209 ret = fe->callback(client->adapter, 210 DVB_FRONTEND_COMPONENT_TUNER, 211 TUA9001_CMD_RESETN, 1); 212 if (ret) 213 goto err_kfree; 214 } 215 216 fe->tuner_priv = dev; 217 memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, 218 sizeof(struct dvb_tuner_ops)); 219 i2c_set_clientdata(client, dev); 220 221 dev_info(&client->dev, "Infineon TUA9001 successfully attached\n"); 222 return 0; 223 err_kfree: 224 kfree(dev); 225 err: 226 dev_dbg(&client->dev, "failed=%d\n", ret); 227 return ret; 228 } 229 230 static int tua9001_remove(struct i2c_client *client) 231 { 232 struct tua9001_dev *dev = i2c_get_clientdata(client); 233 struct dvb_frontend *fe = dev->fe; 234 int ret; 235 236 dev_dbg(&client->dev, "\n"); 237 238 if (fe->callback) { 239 ret = fe->callback(client->adapter, 240 DVB_FRONTEND_COMPONENT_TUNER, 241 TUA9001_CMD_CEN, 0); 242 if (ret) 243 dev_err(&client->dev, "Tuner disable failed (%pe)\n", ERR_PTR(ret)); 244 } 245 kfree(dev); 246 return 0; 247 } 248 249 static const struct i2c_device_id tua9001_id_table[] = { 250 {"tua9001", 0}, 251 {} 252 }; 253 MODULE_DEVICE_TABLE(i2c, tua9001_id_table); 254 255 static struct i2c_driver tua9001_driver = { 256 .driver = { 257 .name = "tua9001", 258 .suppress_bind_attrs = true, 259 }, 260 .probe = tua9001_probe, 261 .remove = tua9001_remove, 262 .id_table = tua9001_id_table, 263 }; 264 265 module_i2c_driver(tua9001_driver); 266 267 MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver"); 268 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 269 MODULE_LICENSE("GPL"); 270