1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Allegro A8293 SEC driver
10 #define A8293_FLAG_ODT 0x10
13 struct i2c_client *client;
15 int volt_slew_nanos_per_mv;
19 * When increasing voltage, do so in minimal steps over time, minimizing
20 * risk of vIN undervoltage.
23 static int a8293_set_voltage_slew(struct a8293_dev *dev,
24 struct i2c_client *client,
25 enum fe_sec_voltage fe_sec_voltage,
31 const int idx_to_mv[] = {
32 0, 12709, 13042, 13375, 14042, 15042, 18042, 18709, 19042
34 const u8 idx_to_reg[] = {
35 0x00, 0x20, 0x21, 0x22, 0x24, 0x27, 0x28, 0x2A, 0x2B
41 dev_dbg(&client->dev, "set_voltage_slew fe_sec_voltage=%d\n",
44 /* Read status register to clear any stale faults. */
45 ret = i2c_master_recv(client, &status, 1);
49 /* Determine previous voltage */
50 switch (dev->reg[0] & 0x2F) {
82 /* Determine new voltage */
83 switch (fe_sec_voltage) {
98 /* Slew to new voltage if new voltage is greater than current voltage */
99 this_volt_idx = prev_volt_idx;
100 if (this_volt_idx < new_volt_idx) {
101 while (this_volt_idx < new_volt_idx) {
102 int delta_mv = idx_to_mv[this_volt_idx+1] - idx_to_mv[this_volt_idx];
103 int min_wait_time = delta_mv * min_nanos_per_mv;
105 reg0 = idx_to_reg[this_volt_idx+1];
106 reg0 |= A8293_FLAG_ODT;
108 ret = i2c_master_send(client, ®0, 1);
113 usleep_range(min_wait_time, min_wait_time * 2);
115 } else { /* Else just set the voltage */
116 reg0 = idx_to_reg[new_volt_idx];
117 reg0 |= A8293_FLAG_ODT;
118 ret = i2c_master_send(client, ®0, 1);
124 /* TMODE=0, TGATE=1 */
126 if (reg1 != dev->reg[1]) {
127 ret = i2c_master_send(client, ®1, 1);
133 usleep_range(1500, 5000);
137 dev_dbg(&client->dev, "failed=%d\n", ret);
142 static int a8293_set_voltage_noslew(struct dvb_frontend *fe,
143 enum fe_sec_voltage fe_sec_voltage)
145 struct a8293_dev *dev = fe->sec_priv;
146 struct i2c_client *client = dev->client;
150 dev_dbg(&client->dev, "set_voltage_noslew fe_sec_voltage=%d\n",
153 switch (fe_sec_voltage) {
154 case SEC_VOLTAGE_OFF:
159 /* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/
163 /* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/
170 if (reg0 != dev->reg[0]) {
171 ret = i2c_master_send(client, ®0, 1);
177 /* TMODE=0, TGATE=1 */
179 if (reg1 != dev->reg[1]) {
180 ret = i2c_master_send(client, ®1, 1);
186 usleep_range(1500, 50000);
189 dev_dbg(&client->dev, "failed=%d\n", ret);
193 static int a8293_set_voltage(struct dvb_frontend *fe,
194 enum fe_sec_voltage fe_sec_voltage)
196 struct a8293_dev *dev = fe->sec_priv;
197 struct i2c_client *client = dev->client;
198 int volt_slew_nanos_per_mv = dev->volt_slew_nanos_per_mv;
200 dev_dbg(&client->dev, "set_voltage volt_slew_nanos_per_mv=%d\n",
201 volt_slew_nanos_per_mv);
203 /* Use slew version if slew rate is set to a sane value */
204 if (volt_slew_nanos_per_mv > 0 && volt_slew_nanos_per_mv < 1600)
205 a8293_set_voltage_slew(dev, client, fe_sec_voltage,
206 volt_slew_nanos_per_mv);
208 a8293_set_voltage_noslew(fe, fe_sec_voltage);
213 static int a8293_probe(struct i2c_client *client)
215 struct a8293_dev *dev;
216 struct a8293_platform_data *pdata = client->dev.platform_data;
217 struct dvb_frontend *fe = pdata->dvb_frontend;
221 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
227 dev->client = client;
228 dev->volt_slew_nanos_per_mv = pdata->volt_slew_nanos_per_mv;
230 /* check if the SEC is there */
231 ret = i2c_master_recv(client, buf, 2);
235 /* override frontend ops */
236 fe->ops.set_voltage = a8293_set_voltage;
238 i2c_set_clientdata(client, dev);
240 dev_info(&client->dev, "Allegro A8293 SEC successfully attached\n");
245 dev_dbg(&client->dev, "failed=%d\n", ret);
249 static void a8293_remove(struct i2c_client *client)
251 struct a8293_dev *dev = i2c_get_clientdata(client);
253 dev_dbg(&client->dev, "\n");
258 static const struct i2c_device_id a8293_id_table[] = {
262 MODULE_DEVICE_TABLE(i2c, a8293_id_table);
264 static struct i2c_driver a8293_driver = {
267 .suppress_bind_attrs = true,
269 .probe = a8293_probe,
270 .remove = a8293_remove,
271 .id_table = a8293_id_table,
274 module_i2c_driver(a8293_driver);
277 MODULE_DESCRIPTION("Allegro A8293 SEC driver");
278 MODULE_LICENSE("GPL");