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 { 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; 222 err_kfree: 223 kfree(dev); 224 err: 225 dev_dbg(&client->dev, "failed=%d\n", ret); 226 return ret; 227 } 228 229 static 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 247 static const struct i2c_device_id tua9001_id_table[] = { 248 { "tua9001" }, 249 {} 250 }; 251 MODULE_DEVICE_TABLE(i2c, tua9001_id_table); 252 253 static 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 263 module_i2c_driver(tua9001_driver); 264 265 MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver"); 266 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 267 MODULE_LICENSE("GPL"); 268