si2157.c (7c2d8ee486b9ebd462dcd0aea1969758522f4c3a) si2157.c (1c35ba3bf97213538b82067acc0f23f18e652226)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
4 *
5 * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6 */
7
8#include "si2157_priv.h"

--- 62 unchanged lines hidden (view full) ---

71 return 0;
72
73err_mutex_unlock:
74 mutex_unlock(&dev->i2c_mutex);
75 dev_dbg(&client->dev, "failed=%d\n", ret);
76 return ret;
77}
78
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
4 *
5 * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6 */
7
8#include "si2157_priv.h"

--- 62 unchanged lines hidden (view full) ---

71 return 0;
72
73err_mutex_unlock:
74 mutex_unlock(&dev->i2c_mutex);
75 dev_dbg(&client->dev, "failed=%d\n", ret);
76 return ret;
77}
78
79static const struct si2157_tuner_info si2157_tuners[] = {
80 { SI2141, false, 0x60, SI2141_60_FIRMWARE, SI2141_A10_FIRMWARE },
81 { SI2141, false, 0x61, SI2141_61_FIRMWARE, SI2141_A10_FIRMWARE },
82 { SI2146, false, 0x11, SI2146_11_FIRMWARE, NULL },
83 { SI2147, false, 0x50, SI2147_50_FIRMWARE, NULL },
84 { SI2148, true, 0x32, SI2148_32_FIRMWARE, SI2158_A20_FIRMWARE },
85 { SI2148, true, 0x33, SI2148_33_FIRMWARE, SI2158_A20_FIRMWARE },
86 { SI2157, false, 0x50, SI2157_50_FIRMWARE, SI2157_A30_FIRMWARE },
87 { SI2158, false, 0x50, SI2158_50_FIRMWARE, SI2158_A20_FIRMWARE },
88 { SI2158, false, 0x51, SI2158_51_FIRMWARE, SI2158_A20_FIRMWARE },
89 { SI2177, false, 0x50, SI2177_50_FIRMWARE, SI2157_A30_FIRMWARE },
90};
91
79static int si2157_load_firmware(struct dvb_frontend *fe,
80 const char *fw_name)
81{
82 struct i2c_client *client = fe->tuner_priv;
83 const struct firmware *fw;
84 int ret, len, remaining;
85 struct si2157_cmd cmd;
86
87 /* request the firmware, this will block and timeout */
92static int si2157_load_firmware(struct dvb_frontend *fe,
93 const char *fw_name)
94{
95 struct i2c_client *client = fe->tuner_priv;
96 const struct firmware *fw;
97 int ret, len, remaining;
98 struct si2157_cmd cmd;
99
100 /* request the firmware, this will block and timeout */
88 ret = request_firmware(&fw, fw_name, &client->dev);
101 ret = firmware_request_nowarn(&fw, fw_name, &client->dev);
89 if (ret)
90 return ret;
91
92 /* firmware should be n chunks of 17 bytes */
93 if (fw->size % 17 != 0) {
94 dev_err(&client->dev, "firmware file '%s' is invalid\n",
95 fw_name);
96 ret = -EINVAL;

--- 22 unchanged lines hidden (view full) ---

119 }
120
121err_release_firmware:
122 release_firmware(fw);
123
124 return ret;
125}
126
102 if (ret)
103 return ret;
104
105 /* firmware should be n chunks of 17 bytes */
106 if (fw->size % 17 != 0) {
107 dev_err(&client->dev, "firmware file '%s' is invalid\n",
108 fw_name);
109 ret = -EINVAL;

--- 22 unchanged lines hidden (view full) ---

132 }
133
134err_release_firmware:
135 release_firmware(fw);
136
137 return ret;
138}
139
140static int si2157_find_and_load_firmware(struct dvb_frontend *fe)
141{
142 struct i2c_client *client = fe->tuner_priv;
143 struct si2157_dev *dev = i2c_get_clientdata(client);
144 const char *fw_alt_name = NULL;
145 unsigned char part_id, rom_id;
146 const char *fw_name = NULL;
147 struct si2157_cmd cmd;
148 bool required = true;
149 int ret, i;
150
151 if (dev->dont_load_firmware) {
152 dev_info(&client->dev,
153 "device is buggy, skipping firmware download\n");
154 return 0;
155 }
156
157 /* query chip revision */
158 memcpy(cmd.args, "\x02", 1);
159 cmd.wlen = 1;
160 cmd.rlen = 13;
161 ret = si2157_cmd_execute(client, &cmd);
162 if (ret)
163 return ret;
164
165 part_id = cmd.args[2];
166 rom_id = cmd.args[12];
167
168 for (i = 0; i < ARRAY_SIZE(si2157_tuners); i++) {
169 if (si2157_tuners[i].part_id != part_id)
170 continue;
171 required = si2157_tuners[i].required;
172 fw_alt_name = si2157_tuners[i].fw_alt_name;
173
174 /* Both part and rom ID match */
175 if (si2157_tuners[i].rom_id == rom_id) {
176 fw_name = si2157_tuners[i].fw_name;
177 break;
178 }
179 }
180
181 if (!fw_name && !fw_alt_name) {
182 dev_err(&client->dev,
183 "unknown chip version Si21%d-%c%c%c ROM 0x%02x\n",
184 part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id);
185 return -EINVAL;
186 }
187
188 dev_info(&client->dev,
189 "found a 'Silicon Labs Si21%d-%c%c%c ROM 0x%02x'\n",
190 part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id);
191
192 if (fw_name)
193 ret = si2157_load_firmware(fe, fw_name);
194 else
195 ret = -ENOENT;
196
197 /* Try alternate name, if any */
198 if (ret == -ENOENT && fw_alt_name)
199 ret = si2157_load_firmware(fe, fw_alt_name);
200
201 if (ret == -ENOENT) {
202 if (!required) {
203 dev_info(&client->dev, "Using ROM firmware.\n");
204 return 0;
205 }
206 dev_err(&client->dev, "Can't continue without a firmware.\n");
207 } else if (ret < 0) {
208 dev_err(&client->dev, "error %d when loading firmware\n", ret);
209 }
210 return ret;
211}
212
127static int si2157_init(struct dvb_frontend *fe)
128{
129 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
130 struct i2c_client *client = fe->tuner_priv;
131 struct si2157_dev *dev = i2c_get_clientdata(client);
213static int si2157_init(struct dvb_frontend *fe)
214{
215 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
216 struct i2c_client *client = fe->tuner_priv;
217 struct si2157_dev *dev = i2c_get_clientdata(client);
132 bool warn_firmware_not_loaded = false;
133 unsigned int chip_id, xtal_trim;
134 bool fw_required = true;
218 unsigned int xtal_trim;
135 struct si2157_cmd cmd;
219 struct si2157_cmd cmd;
136 const char *fw_name;
137 int ret;
138
139 dev_dbg(&client->dev, "\n");
140
141 /* Try to get Xtal trim property, to verify tuner still running */
142 memcpy(cmd.args, "\x15\x00\x02\x04", 4);
143 cmd.wlen = 4;
144 cmd.rlen = 4;

--- 26 unchanged lines hidden (view full) ---

171 if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
172 memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7);
173 cmd.wlen = 7;
174 ret = si2157_cmd_execute(client, &cmd);
175 if (ret)
176 goto err;
177 }
178
220 int ret;
221
222 dev_dbg(&client->dev, "\n");
223
224 /* Try to get Xtal trim property, to verify tuner still running */
225 memcpy(cmd.args, "\x15\x00\x02\x04", 4);
226 cmd.wlen = 4;
227 cmd.rlen = 4;

--- 26 unchanged lines hidden (view full) ---

254 if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
255 memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7);
256 cmd.wlen = 7;
257 ret = si2157_cmd_execute(client, &cmd);
258 if (ret)
259 goto err;
260 }
261
179 if (dev->dont_load_firmware) {
180 dev_info(&client->dev, "device is buggy, skipping firmware download\n");
181 goto skip_fw_download;
182 }
183
184 /* query chip revision */
185 memcpy(cmd.args, "\x02", 1);
186 cmd.wlen = 1;
187 cmd.rlen = 13;
188 ret = si2157_cmd_execute(client, &cmd);
189 if (ret)
262 /* Try to load the firmware */
263 ret = si2157_find_and_load_firmware(fe);
264 if (ret < 0)
190 goto err;
191
265 goto err;
266
192 chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
193 cmd.args[4] << 0;
194
195 #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0)
196 #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
197 #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0)
198 #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
199 #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
200 #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
201 #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0)
202
203 switch (chip_id) {
204 case SI2158_A20:
205 case SI2148_A20:
206 fw_name = SI2158_A20_FIRMWARE;
207 break;
208 case SI2141_A10:
209 fw_name = SI2141_A10_FIRMWARE;
210 break;
211 case SI2157_A30:
212 fw_required = false;
213 fallthrough;
214 case SI2177_A30:
215 fw_name = SI2157_A30_FIRMWARE;
216 break;
217 case SI2147_A30:
218 case SI2146_A10:
219 fw_name = NULL;
220 break;
221 default:
222 dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
223 cmd.args[2], cmd.args[1],
224 cmd.args[3], cmd.args[4]);
225 ret = -EINVAL;
226 goto err;
227 }
228
229 dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
230 cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
231
232 if (fw_name == NULL)
233 goto skip_fw_download;
234
235 ret = si2157_load_firmware(fe, fw_name);
236 if (fw_required && ret == -ENOENT)
237 warn_firmware_not_loaded = true;
238 else if (ret < 0) {
239 dev_err(&client->dev, "error %d when loading firmware file '%s'\n",
240 ret, fw_name);
241 goto err;
242 }
243
244skip_fw_download:
245 /* reboot the tuner with new firmware? */
246 memcpy(cmd.args, "\x01\x01", 2);
247 cmd.wlen = 2;
248 cmd.rlen = 1;
249 ret = si2157_cmd_execute(client, &cmd);
250 if (ret)
251 goto err;
252
253 /* query firmware version */
254 memcpy(cmd.args, "\x11", 1);
255 cmd.wlen = 1;
256 cmd.rlen = 10;
257 ret = si2157_cmd_execute(client, &cmd);
258 if (ret)
259 goto err;
260
267 /* reboot the tuner with new firmware? */
268 memcpy(cmd.args, "\x01\x01", 2);
269 cmd.wlen = 2;
270 cmd.rlen = 1;
271 ret = si2157_cmd_execute(client, &cmd);
272 if (ret)
273 goto err;
274
275 /* query firmware version */
276 memcpy(cmd.args, "\x11", 1);
277 cmd.wlen = 1;
278 cmd.rlen = 10;
279 ret = si2157_cmd_execute(client, &cmd);
280 if (ret)
281 goto err;
282
261 if (warn_firmware_not_loaded) {
262 dev_warn(&client->dev, "firmware file '%s' not found. Using firmware from eeprom.\n",
263 fw_name);
264 warn_firmware_not_loaded = false;
265 }
266 dev_info(&client->dev, "firmware version: %c.%c.%d\n",
267 cmd.args[6], cmd.args[7], cmd.args[8]);
268
269 /* enable tuner status flags */
270 memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6);
271 cmd.wlen = 6;
272 cmd.rlen = 1;
273 ret = si2157_cmd_execute(client, &cmd);

--- 19 unchanged lines hidden (view full) ---

293 c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
294 /* start statistics polling */
295 schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(1000));
296
297 dev->active = true;
298 return 0;
299
300err:
283 dev_info(&client->dev, "firmware version: %c.%c.%d\n",
284 cmd.args[6], cmd.args[7], cmd.args[8]);
285
286 /* enable tuner status flags */
287 memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6);
288 cmd.wlen = 6;
289 cmd.rlen = 1;
290 ret = si2157_cmd_execute(client, &cmd);

--- 19 unchanged lines hidden (view full) ---

310 c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
311 /* start statistics polling */
312 schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(1000));
313
314 dev->active = true;
315 return 0;
316
317err:
301 if (warn_firmware_not_loaded)
302 dev_err(&client->dev,
303 "firmware file '%s' not found. Can't continue without a firmware.\n",
304 fw_name);
305
306 dev_dbg(&client->dev, "failed=%d\n", ret);
307 return ret;
308}
309
310static int si2157_sleep(struct dvb_frontend *fe)
311{
312 struct i2c_client *client = fe->tuner_priv;
313 struct si2157_dev *dev = i2c_get_clientdata(client);

--- 649 unchanged lines hidden (view full) ---

963module_i2c_driver(si2157_driver);
964
965MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
966MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
967MODULE_LICENSE("GPL");
968MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
969MODULE_FIRMWARE(SI2141_A10_FIRMWARE);
970MODULE_FIRMWARE(SI2157_A30_FIRMWARE);
318 dev_dbg(&client->dev, "failed=%d\n", ret);
319 return ret;
320}
321
322static int si2157_sleep(struct dvb_frontend *fe)
323{
324 struct i2c_client *client = fe->tuner_priv;
325 struct si2157_dev *dev = i2c_get_clientdata(client);

--- 649 unchanged lines hidden (view full) ---

975module_i2c_driver(si2157_driver);
976
977MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
978MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
979MODULE_LICENSE("GPL");
980MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
981MODULE_FIRMWARE(SI2141_A10_FIRMWARE);
982MODULE_FIRMWARE(SI2157_A30_FIRMWARE);
983MODULE_FIRMWARE(SI2141_60_FIRMWARE);
984MODULE_FIRMWARE(SI2141_61_FIRMWARE);
985MODULE_FIRMWARE(SI2146_11_FIRMWARE);
986MODULE_FIRMWARE(SI2147_50_FIRMWARE);
987MODULE_FIRMWARE(SI2148_32_FIRMWARE);
988MODULE_FIRMWARE(SI2148_33_FIRMWARE);
989MODULE_FIRMWARE(SI2157_50_FIRMWARE);
990MODULE_FIRMWARE(SI2158_50_FIRMWARE);
991MODULE_FIRMWARE(SI2158_51_FIRMWARE);
992MODULE_FIRMWARE(SI2177_50_FIRMWARE);