brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · bf2773c Raw
279 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Allegro A8293 SEC driver4 *5 * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>6 */7 8#include "a8293.h"9 10#define A8293_FLAG_ODT			0x1011 12struct a8293_dev {13	struct i2c_client *client;14	u8 reg[2];15	int volt_slew_nanos_per_mv;16};17 18/*19 * When increasing voltage, do so in minimal steps over time, minimizing20 * risk of vIN undervoltage.21 */22 23static int a8293_set_voltage_slew(struct a8293_dev *dev,24				  struct i2c_client *client,25				  enum fe_sec_voltage fe_sec_voltage,26				  int min_nanos_per_mv)27{28	int ret;29	u8 reg0, reg1;30	int new_volt_idx;31	const int idx_to_mv[] = {32		0,    12709, 13042, 13375, 14042, 15042, 18042, 18709, 1904233	};34	const u8 idx_to_reg[] = {35		0x00, 0x20,  0x21,  0x22,  0x24,  0x27,  0x28,  0x2A,  0x2B36	};37	int this_volt_idx;38	u8 status;39	int prev_volt_idx;40 41	dev_dbg(&client->dev, "set_voltage_slew fe_sec_voltage=%d\n",42		fe_sec_voltage);43 44	/* Read status register to clear any stale faults. */45	ret = i2c_master_recv(client, &status, 1);46	if (ret < 0)47		goto err;48 49	/* Determine previous voltage */50	switch (dev->reg[0] & 0x2F) {51	case 0x00:52		prev_volt_idx = 0;53		break;54	case 0x20:55		prev_volt_idx = 1;56		break;57	case 0x21:58		prev_volt_idx = 2;59		break;60	case 0x22:61		prev_volt_idx = 3;62		break;63	case 0x24:64		prev_volt_idx = 4;65		break;66	case 0x27:67		prev_volt_idx = 5;68		break;69	case 0x28:70		prev_volt_idx = 6;71		break;72	case 0x2A:73		prev_volt_idx = 7;74		break;75	case 0x2B:76		prev_volt_idx = 8;77		break;78	default:79		prev_volt_idx = 0;80	}81 82	/* Determine new voltage */83	switch (fe_sec_voltage) {84	case SEC_VOLTAGE_OFF:85		new_volt_idx = 0;86		break;87	case SEC_VOLTAGE_13:88		new_volt_idx = 2;89		break;90	case SEC_VOLTAGE_18:91		new_volt_idx = 6;92		break;93	default:94		ret = -EINVAL;95		goto err;96	}97 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;104 105			reg0 = idx_to_reg[this_volt_idx+1];106			reg0 |= A8293_FLAG_ODT;107 108			ret = i2c_master_send(client, &reg0, 1);109			if (ret < 0)110				goto err;111			dev->reg[0] = reg0;112			this_volt_idx++;113			usleep_range(min_wait_time, min_wait_time * 2);114		}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, &reg0, 1);119		if (ret < 0)120			goto err;121		dev->reg[0] = reg0;122	}123 124	/* TMODE=0, TGATE=1 */125	reg1 = 0x82;126	if (reg1 != dev->reg[1]) {127		ret = i2c_master_send(client, &reg1, 1);128		if (ret < 0)129			goto err;130		dev->reg[1] = reg1;131	}132 133	usleep_range(1500, 5000);134 135	return 0;136err:137	dev_dbg(&client->dev, "failed=%d\n", ret);138	return ret;139}140 141 142static int a8293_set_voltage_noslew(struct dvb_frontend *fe,143				    enum fe_sec_voltage fe_sec_voltage)144{145	struct a8293_dev *dev = fe->sec_priv;146	struct i2c_client *client = dev->client;147	int ret;148	u8 reg0, reg1;149 150	dev_dbg(&client->dev, "set_voltage_noslew fe_sec_voltage=%d\n",151		fe_sec_voltage);152 153	switch (fe_sec_voltage) {154	case SEC_VOLTAGE_OFF:155		/* ENB=0 */156		reg0 = 0x10;157		break;158	case SEC_VOLTAGE_13:159		/* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/160		reg0 = 0x31;161		break;162	case SEC_VOLTAGE_18:163		/* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/164		reg0 = 0x38;165		break;166	default:167		ret = -EINVAL;168		goto err;169	}170	if (reg0 != dev->reg[0]) {171		ret = i2c_master_send(client, &reg0, 1);172		if (ret < 0)173			goto err;174		dev->reg[0] = reg0;175	}176 177	/* TMODE=0, TGATE=1 */178	reg1 = 0x82;179	if (reg1 != dev->reg[1]) {180		ret = i2c_master_send(client, &reg1, 1);181		if (ret < 0)182			goto err;183		dev->reg[1] = reg1;184	}185 186	usleep_range(1500, 50000);187	return 0;188err:189	dev_dbg(&client->dev, "failed=%d\n", ret);190	return ret;191}192 193static int a8293_set_voltage(struct dvb_frontend *fe,194			     enum fe_sec_voltage fe_sec_voltage)195{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;199 200	dev_dbg(&client->dev, "set_voltage volt_slew_nanos_per_mv=%d\n",201		volt_slew_nanos_per_mv);202 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);207	else208		a8293_set_voltage_noslew(fe, fe_sec_voltage);209 210	return 0;211}212 213static int a8293_probe(struct i2c_client *client)214{215	struct a8293_dev *dev;216	struct a8293_platform_data *pdata = client->dev.platform_data;217	struct dvb_frontend *fe = pdata->dvb_frontend;218	int ret;219	u8 buf[2];220 221	dev = kzalloc(sizeof(*dev), GFP_KERNEL);222	if (!dev) {223		ret = -ENOMEM;224		goto err;225	}226 227	dev->client = client;228	dev->volt_slew_nanos_per_mv = pdata->volt_slew_nanos_per_mv;229 230	/* check if the SEC is there */231	ret = i2c_master_recv(client, buf, 2);232	if (ret < 0)233		goto err_kfree;234 235	/* override frontend ops */236	fe->ops.set_voltage = a8293_set_voltage;237	fe->sec_priv = dev;238	i2c_set_clientdata(client, dev);239 240	dev_info(&client->dev, "Allegro A8293 SEC successfully attached\n");241	return 0;242err_kfree:243	kfree(dev);244err:245	dev_dbg(&client->dev, "failed=%d\n", ret);246	return ret;247}248 249static void a8293_remove(struct i2c_client *client)250{251	struct a8293_dev *dev = i2c_get_clientdata(client);252 253	dev_dbg(&client->dev, "\n");254 255	kfree(dev);256}257 258static const struct i2c_device_id a8293_id_table[] = {259	{ "a8293" },260	{}261};262MODULE_DEVICE_TABLE(i2c, a8293_id_table);263 264static struct i2c_driver a8293_driver = {265	.driver = {266		.name	= "a8293",267		.suppress_bind_attrs = true,268	},269	.probe		= a8293_probe,270	.remove		= a8293_remove,271	.id_table	= a8293_id_table,272};273 274module_i2c_driver(a8293_driver);275 276MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");277MODULE_DESCRIPTION("Allegro A8293 SEC driver");278MODULE_LICENSE("GPL");279