2 * Silicon Labs Si2157 silicon tuner driver
4 * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include "si2157_priv.h"
19 /* execute firmware command */
20 static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
23 unsigned long timeout;
25 mutex_lock(&s->i2c_mutex);
28 /* write cmd and args for firmware */
29 ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
31 goto err_mutex_unlock;
32 } else if (ret != cmd->wlen) {
34 goto err_mutex_unlock;
39 /* wait cmd execution terminate */
41 timeout = jiffies + msecs_to_jiffies(TIMEOUT);
42 while (!time_after(jiffies, timeout)) {
43 ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
45 goto err_mutex_unlock;
46 } else if (ret != cmd->rlen) {
48 goto err_mutex_unlock;
52 if ((cmd->args[0] >> 7) & 0x01)
56 dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
58 jiffies_to_msecs(jiffies) -
59 (jiffies_to_msecs(timeout) - TIMEOUT));
61 if (!((cmd->args[0] >> 7) & 0x01)) {
63 goto err_mutex_unlock;
70 mutex_unlock(&s->i2c_mutex);
76 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
80 static int si2157_init(struct dvb_frontend *fe)
82 struct si2157 *s = fe->tuner_priv;
84 dev_dbg(&s->client->dev, "%s:\n", __func__);
91 static int si2157_sleep(struct dvb_frontend *fe)
93 struct si2157 *s = fe->tuner_priv;
95 struct si2157_cmd cmd;
97 dev_dbg(&s->client->dev, "%s:\n", __func__);
101 memcpy(cmd.args, "\x13", 1);
104 ret = si2157_cmd_execute(s, &cmd);
110 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
114 static int si2157_set_params(struct dvb_frontend *fe)
116 struct si2157 *s = fe->tuner_priv;
117 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
119 struct si2157_cmd cmd;
121 dev_dbg(&s->client->dev,
122 "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
123 __func__, c->delivery_system, c->frequency,
149 ret = si2157_cmd_execute(s, &cmd);
156 ret = si2157_cmd_execute(s, &cmd);
164 ret = si2157_cmd_execute(s, &cmd);
173 cmd.args[4] = (c->frequency >> 0) & 0xff;
174 cmd.args[5] = (c->frequency >> 8) & 0xff;
175 cmd.args[6] = (c->frequency >> 16) & 0xff;
176 cmd.args[7] = (c->frequency >> 24) & 0xff;
179 ret = si2157_cmd_execute(s, &cmd);
185 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
189 static const struct dvb_tuner_ops si2157_tuner_ops = {
191 .name = "Silicon Labs Si2157",
192 .frequency_min = 110000000,
193 .frequency_max = 862000000,
197 .sleep = si2157_sleep,
198 .set_params = si2157_set_params,
201 static int si2157_probe(struct i2c_client *client,
202 const struct i2c_device_id *id)
204 struct si2157_config *cfg = client->dev.platform_data;
205 struct dvb_frontend *fe = cfg->fe;
207 struct si2157_cmd cmd;
210 s = kzalloc(sizeof(struct si2157), GFP_KERNEL);
213 dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
219 mutex_init(&s->i2c_mutex);
221 /* check if the tuner is there */
224 ret = si2157_cmd_execute(s, &cmd);
229 memcpy(&fe->ops.tuner_ops, &si2157_tuner_ops,
230 sizeof(struct dvb_tuner_ops));
232 i2c_set_clientdata(client, s);
234 dev_info(&s->client->dev,
235 "%s: Silicon Labs Si2157 successfully attached\n",
239 dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
245 static int si2157_remove(struct i2c_client *client)
247 struct si2157 *s = i2c_get_clientdata(client);
248 struct dvb_frontend *fe = s->fe;
250 dev_dbg(&client->dev, "%s:\n", __func__);
252 memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
253 fe->tuner_priv = NULL;
259 static const struct i2c_device_id si2157_id[] = {
263 MODULE_DEVICE_TABLE(i2c, si2157_id);
265 static struct i2c_driver si2157_driver = {
267 .owner = THIS_MODULE,
270 .probe = si2157_probe,
271 .remove = si2157_remove,
272 .id_table = si2157_id,
275 module_i2c_driver(si2157_driver);
277 MODULE_DESCRIPTION("Silicon Labs Si2157 silicon tuner driver");
278 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
279 MODULE_LICENSE("GPL");