aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb-frontends/si2165.c149
-rw-r--r--drivers/media/dvb-frontends/si2165.h22
2 files changed, 171 insertions, 0 deletions
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 849c3c421262..55127d4cb747 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -40,6 +40,8 @@
40 */ 40 */
41 41
42struct si2165_state { 42struct si2165_state {
43 struct i2c_client *client;
44
43 struct i2c_adapter *i2c; 45 struct i2c_adapter *i2c;
44 46
45 struct dvb_frontend fe; 47 struct dvb_frontend fe;
@@ -1163,6 +1165,153 @@ error:
1163} 1165}
1164EXPORT_SYMBOL(si2165_attach); 1166EXPORT_SYMBOL(si2165_attach);
1165 1167
1168static int si2165_probe(struct i2c_client *client,
1169 const struct i2c_device_id *id)
1170{
1171 struct si2165_state *state = NULL;
1172 struct si2165_platform_data *pdata = client->dev.platform_data;
1173 int n;
1174 int ret = 0;
1175 u8 val;
1176 char rev_char;
1177 const char *chip_name;
1178
1179 /* allocate memory for the internal state */
1180 state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL);
1181 if (state == NULL) {
1182 ret = -ENOMEM;
1183 goto error;
1184 }
1185
1186 /* setup the state */
1187 state->client = client;
1188 state->i2c = client->adapter;
1189 state->config.i2c_addr = client->addr;
1190 state->config.chip_mode = pdata->chip_mode;
1191 state->config.ref_freq_Hz = pdata->ref_freq_Hz;
1192 state->config.inversion = pdata->inversion;
1193
1194 if (state->config.ref_freq_Hz < 4000000
1195 || state->config.ref_freq_Hz > 27000000) {
1196 dev_err(&state->i2c->dev, "%s: ref_freq of %d Hz not supported by this driver\n",
1197 KBUILD_MODNAME, state->config.ref_freq_Hz);
1198 ret = -EINVAL;
1199 goto error;
1200 }
1201
1202 /* create dvb_frontend */
1203 memcpy(&state->fe.ops, &si2165_ops,
1204 sizeof(struct dvb_frontend_ops));
1205 state->fe.ops.release = NULL;
1206 state->fe.demodulator_priv = state;
1207 i2c_set_clientdata(client, state);
1208
1209 /* powerup */
1210 ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
1211 if (ret < 0)
1212 goto nodev_error;
1213
1214 ret = si2165_readreg8(state, 0x0000, &val);
1215 if (ret < 0)
1216 goto nodev_error;
1217 if (val != state->config.chip_mode)
1218 goto nodev_error;
1219
1220 ret = si2165_readreg8(state, 0x0023, &state->chip_revcode);
1221 if (ret < 0)
1222 goto nodev_error;
1223
1224 ret = si2165_readreg8(state, 0x0118, &state->chip_type);
1225 if (ret < 0)
1226 goto nodev_error;
1227
1228 /* powerdown */
1229 ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
1230 if (ret < 0)
1231 goto nodev_error;
1232
1233 if (state->chip_revcode < 26)
1234 rev_char = 'A' + state->chip_revcode;
1235 else
1236 rev_char = '?';
1237
1238 switch (state->chip_type) {
1239 case 0x06:
1240 chip_name = "Si2161";
1241 state->has_dvbt = true;
1242 break;
1243 case 0x07:
1244 chip_name = "Si2165";
1245 state->has_dvbt = true;
1246 state->has_dvbc = true;
1247 break;
1248 default:
1249 dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n",
1250 KBUILD_MODNAME, state->chip_type, state->chip_revcode);
1251 goto nodev_error;
1252 }
1253
1254 dev_info(&state->i2c->dev,
1255 "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n",
1256 KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
1257 state->chip_revcode);
1258
1259 strlcat(state->fe.ops.info.name, chip_name,
1260 sizeof(state->fe.ops.info.name));
1261
1262 n = 0;
1263 if (state->has_dvbt) {
1264 state->fe.ops.delsys[n++] = SYS_DVBT;
1265 strlcat(state->fe.ops.info.name, " DVB-T",
1266 sizeof(state->fe.ops.info.name));
1267 }
1268 if (state->has_dvbc) {
1269 state->fe.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
1270 strlcat(state->fe.ops.info.name, " DVB-C",
1271 sizeof(state->fe.ops.info.name));
1272 }
1273
1274 /* return fe pointer */
1275 *pdata->fe = &state->fe;
1276
1277 return 0;
1278
1279nodev_error:
1280 ret = -ENODEV;
1281error:
1282 kfree(state);
1283 dev_dbg(&client->dev, "failed=%d\n", ret);
1284 return ret;
1285}
1286
1287static int si2165_remove(struct i2c_client *client)
1288{
1289 struct si2165_state *state = i2c_get_clientdata(client);
1290
1291 dev_dbg(&client->dev, "\n");
1292
1293 kfree(state);
1294 return 0;
1295}
1296
1297static const struct i2c_device_id si2165_id_table[] = {
1298 {"si2165", 0},
1299 {}
1300};
1301MODULE_DEVICE_TABLE(i2c, si2165_id_table);
1302
1303static struct i2c_driver si2165_driver = {
1304 .driver = {
1305 .owner = THIS_MODULE,
1306 .name = "si2165",
1307 },
1308 .probe = si2165_probe,
1309 .remove = si2165_remove,
1310 .id_table = si2165_id_table,
1311};
1312
1313module_i2c_driver(si2165_driver);
1314
1166module_param(debug, int, 0644); 1315module_param(debug, int, 0644);
1167MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 1316MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
1168 1317
diff --git a/drivers/media/dvb-frontends/si2165.h b/drivers/media/dvb-frontends/si2165.h
index 8a15d6a9c552..abbebc9edf0c 100644
--- a/drivers/media/dvb-frontends/si2165.h
+++ b/drivers/media/dvb-frontends/si2165.h
@@ -28,6 +28,28 @@ enum {
28 SI2165_MODE_PLL_XTAL = 0x21 28 SI2165_MODE_PLL_XTAL = 0x21
29}; 29};
30 30
31/* I2C addresses
32 * possible values: 0x64,0x65,0x66,0x67
33 */
34struct si2165_platform_data {
35 /*
36 * frontend
37 * returned by driver
38 */
39 struct dvb_frontend **fe;
40
41 /* external clock or XTAL */
42 u8 chip_mode;
43
44 /* frequency of external clock or xtal in Hz
45 * possible values: 4000000, 16000000, 20000000, 240000000, 27000000
46 */
47 u32 ref_freq_Hz;
48
49 /* invert the spectrum */
50 bool inversion;
51};
52
31struct si2165_config { 53struct si2165_config {
32 /* i2c addr 54 /* i2c addr
33 * possible values: 0x64,0x65,0x66,0x67 */ 55 * possible values: 0x64,0x65,0x66,0x67 */