diff options
-rw-r--r-- | drivers/media/dvb-frontends/si2165.c | 149 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/si2165.h | 22 |
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 | ||
42 | struct si2165_state { | 42 | struct 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 | } |
1164 | EXPORT_SYMBOL(si2165_attach); | 1166 | EXPORT_SYMBOL(si2165_attach); |
1165 | 1167 | ||
1168 | static 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 | |||
1279 | nodev_error: | ||
1280 | ret = -ENODEV; | ||
1281 | error: | ||
1282 | kfree(state); | ||
1283 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
1284 | return ret; | ||
1285 | } | ||
1286 | |||
1287 | static 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 | |||
1297 | static const struct i2c_device_id si2165_id_table[] = { | ||
1298 | {"si2165", 0}, | ||
1299 | {} | ||
1300 | }; | ||
1301 | MODULE_DEVICE_TABLE(i2c, si2165_id_table); | ||
1302 | |||
1303 | static 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 | |||
1313 | module_i2c_driver(si2165_driver); | ||
1314 | |||
1166 | module_param(debug, int, 0644); | 1315 | module_param(debug, int, 0644); |
1167 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | 1316 | MODULE_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 | */ | ||
34 | struct 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 | |||
31 | struct si2165_config { | 53 | struct si2165_config { |
32 | /* i2c addr | 54 | /* i2c addr |
33 | * possible values: 0x64,0x65,0x66,0x67 */ | 55 | * possible values: 0x64,0x65,0x66,0x67 */ |