diff options
author | Antti Palosaari <crope@iki.fi> | 2014-04-10 20:58:10 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-04-23 08:47:33 -0400 |
commit | 930a873081986393f6e7e0fb9275753c1485277b (patch) | |
tree | fd40f7facb9fe2448f8dfe4220cdafe6d62aae8c /drivers/media/tuners/si2157.c | |
parent | 701b57ee3387b8e3749845b02310b5625fbd8da0 (diff) |
[media] si2157: Silicon Labs Si2157 silicon tuner driver
Silicon Labs Si2157 silicon tuner driver.
Currently it supports only DVB-T.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/tuners/si2157.c')
-rw-r--r-- | drivers/media/tuners/si2157.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c new file mode 100644 index 000000000000..953f2e3f1489 --- /dev/null +++ b/drivers/media/tuners/si2157.c | |||
@@ -0,0 +1,244 @@ | |||
1 | #include "si2157_priv.h" | ||
2 | |||
3 | /* execute firmware command */ | ||
4 | static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) | ||
5 | { | ||
6 | int ret; | ||
7 | u8 buf[1]; | ||
8 | unsigned long timeout; | ||
9 | |||
10 | mutex_lock(&s->i2c_mutex); | ||
11 | |||
12 | if (cmd->len) { | ||
13 | /* write cmd and args for firmware */ | ||
14 | ret = i2c_master_send(s->client, cmd->args, cmd->len); | ||
15 | if (ret < 0) { | ||
16 | goto err_mutex_unlock; | ||
17 | } else if (ret != cmd->len) { | ||
18 | ret = -EREMOTEIO; | ||
19 | goto err_mutex_unlock; | ||
20 | } | ||
21 | } | ||
22 | |||
23 | /* wait cmd execution terminate */ | ||
24 | #define TIMEOUT 80 | ||
25 | timeout = jiffies + msecs_to_jiffies(TIMEOUT); | ||
26 | while (!time_after(jiffies, timeout)) { | ||
27 | ret = i2c_master_recv(s->client, buf, 1); | ||
28 | if (ret < 0) { | ||
29 | goto err_mutex_unlock; | ||
30 | } else if (ret != 1) { | ||
31 | ret = -EREMOTEIO; | ||
32 | goto err_mutex_unlock; | ||
33 | } | ||
34 | |||
35 | /* firmware ready? */ | ||
36 | if ((buf[0] >> 7) & 0x01) | ||
37 | break; | ||
38 | } | ||
39 | |||
40 | dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", __func__, | ||
41 | jiffies_to_msecs(jiffies) - | ||
42 | (jiffies_to_msecs(timeout) - TIMEOUT)); | ||
43 | |||
44 | if (!(buf[0] >> 7) & 0x01) { | ||
45 | ret = -ETIMEDOUT; | ||
46 | goto err_mutex_unlock; | ||
47 | } else { | ||
48 | ret = 0; | ||
49 | } | ||
50 | |||
51 | err_mutex_unlock: | ||
52 | mutex_unlock(&s->i2c_mutex); | ||
53 | if (ret) | ||
54 | goto err; | ||
55 | |||
56 | return 0; | ||
57 | err: | ||
58 | dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | static int si2157_init(struct dvb_frontend *fe) | ||
63 | { | ||
64 | struct si2157 *s = fe->tuner_priv; | ||
65 | |||
66 | dev_dbg(&s->client->dev, "%s:\n", __func__); | ||
67 | |||
68 | s->active = true; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int si2157_sleep(struct dvb_frontend *fe) | ||
74 | { | ||
75 | struct si2157 *s = fe->tuner_priv; | ||
76 | |||
77 | dev_dbg(&s->client->dev, "%s:\n", __func__); | ||
78 | |||
79 | s->active = false; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int si2157_set_params(struct dvb_frontend *fe) | ||
85 | { | ||
86 | struct si2157 *s = fe->tuner_priv; | ||
87 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
88 | int ret; | ||
89 | struct si2157_cmd cmd; | ||
90 | |||
91 | dev_dbg(&s->client->dev, | ||
92 | "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", | ||
93 | __func__, c->delivery_system, c->frequency, | ||
94 | c->bandwidth_hz); | ||
95 | |||
96 | if (!s->active) { | ||
97 | ret = -EAGAIN; | ||
98 | goto err; | ||
99 | } | ||
100 | |||
101 | /* configure? */ | ||
102 | cmd.args[0] = 0xc0; | ||
103 | cmd.args[1] = 0x00; | ||
104 | cmd.args[2] = 0x0c; | ||
105 | cmd.args[3] = 0x00; | ||
106 | cmd.args[4] = 0x00; | ||
107 | cmd.args[5] = 0x01; | ||
108 | cmd.args[6] = 0x01; | ||
109 | cmd.args[7] = 0x01; | ||
110 | cmd.args[8] = 0x01; | ||
111 | cmd.args[9] = 0x01; | ||
112 | cmd.args[10] = 0x01; | ||
113 | cmd.args[11] = 0x02; | ||
114 | cmd.args[12] = 0x00; | ||
115 | cmd.args[13] = 0x00; | ||
116 | cmd.args[14] = 0x01; | ||
117 | cmd.len = 15; | ||
118 | ret = si2157_cmd_execute(s, &cmd); | ||
119 | if (ret) | ||
120 | goto err; | ||
121 | |||
122 | cmd.args[0] = 0x02; | ||
123 | cmd.len = 1; | ||
124 | ret = si2157_cmd_execute(s, &cmd); | ||
125 | if (ret) | ||
126 | goto err; | ||
127 | |||
128 | cmd.args[0] = 0x01; | ||
129 | cmd.args[1] = 0x01; | ||
130 | cmd.len = 2; | ||
131 | ret = si2157_cmd_execute(s, &cmd); | ||
132 | if (ret) | ||
133 | goto err; | ||
134 | |||
135 | /* set frequency */ | ||
136 | cmd.args[0] = 0x41; | ||
137 | cmd.args[1] = 0x00; | ||
138 | cmd.args[2] = 0x00; | ||
139 | cmd.args[3] = 0x00; | ||
140 | cmd.args[4] = (c->frequency >> 0) & 0xff; | ||
141 | cmd.args[5] = (c->frequency >> 8) & 0xff; | ||
142 | cmd.args[6] = (c->frequency >> 16) & 0xff; | ||
143 | cmd.args[7] = (c->frequency >> 24) & 0xff; | ||
144 | cmd.len = 8; | ||
145 | ret = si2157_cmd_execute(s, &cmd); | ||
146 | if (ret) | ||
147 | goto err; | ||
148 | |||
149 | return 0; | ||
150 | err: | ||
151 | dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static const struct dvb_tuner_ops si2157_tuner_ops = { | ||
156 | .info = { | ||
157 | .name = "Silicon Labs Si2157", | ||
158 | .frequency_min = 174000000, | ||
159 | .frequency_max = 862000000, | ||
160 | }, | ||
161 | |||
162 | .init = si2157_init, | ||
163 | .sleep = si2157_sleep, | ||
164 | .set_params = si2157_set_params, | ||
165 | }; | ||
166 | |||
167 | static int si2157_probe(struct i2c_client *client, | ||
168 | const struct i2c_device_id *id) | ||
169 | { | ||
170 | struct si2157_config *cfg = client->dev.platform_data; | ||
171 | struct dvb_frontend *fe = cfg->fe; | ||
172 | struct si2157 *s; | ||
173 | struct si2157_cmd cmd; | ||
174 | int ret; | ||
175 | |||
176 | s = kzalloc(sizeof(struct si2157), GFP_KERNEL); | ||
177 | if (!s) { | ||
178 | ret = -ENOMEM; | ||
179 | dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); | ||
180 | goto err; | ||
181 | } | ||
182 | |||
183 | s->client = client; | ||
184 | s->fe = cfg->fe; | ||
185 | mutex_init(&s->i2c_mutex); | ||
186 | |||
187 | /* check if the tuner is there */ | ||
188 | cmd.len = 0; | ||
189 | ret = si2157_cmd_execute(s, &cmd); | ||
190 | if (ret) | ||
191 | goto err; | ||
192 | |||
193 | fe->tuner_priv = s; | ||
194 | memcpy(&fe->ops.tuner_ops, &si2157_tuner_ops, | ||
195 | sizeof(struct dvb_tuner_ops)); | ||
196 | |||
197 | i2c_set_clientdata(client, s); | ||
198 | |||
199 | dev_info(&s->client->dev, | ||
200 | "%s: Silicon Labs Si2157 successfully attached\n", | ||
201 | KBUILD_MODNAME); | ||
202 | return 0; | ||
203 | err: | ||
204 | dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); | ||
205 | kfree(s); | ||
206 | |||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | static int si2157_remove(struct i2c_client *client) | ||
211 | { | ||
212 | struct si2157 *s = i2c_get_clientdata(client); | ||
213 | struct dvb_frontend *fe = s->fe; | ||
214 | |||
215 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
216 | |||
217 | memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); | ||
218 | fe->tuner_priv = NULL; | ||
219 | kfree(s); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static const struct i2c_device_id si2157_id[] = { | ||
225 | {"si2157", 0}, | ||
226 | {} | ||
227 | }; | ||
228 | MODULE_DEVICE_TABLE(i2c, si2157_id); | ||
229 | |||
230 | static struct i2c_driver si2157_driver = { | ||
231 | .driver = { | ||
232 | .owner = THIS_MODULE, | ||
233 | .name = "si2157", | ||
234 | }, | ||
235 | .probe = si2157_probe, | ||
236 | .remove = si2157_remove, | ||
237 | .id_table = si2157_id, | ||
238 | }; | ||
239 | |||
240 | module_i2c_driver(si2157_driver); | ||
241 | |||
242 | MODULE_DESCRIPTION("Silicon Labs Si2157 silicon tuner driver"); | ||
243 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
244 | MODULE_LICENSE("GPL"); | ||