cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

da9052-hwmon.c (14003B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * HWMON Driver for Dialog DA9052
      4 *
      5 * Copyright(c) 2012 Dialog Semiconductor Ltd.
      6 *
      7 * Author: David Dajun Chen <dchen@diasemi.com>
      8 */
      9
     10#include <linux/err.h>
     11#include <linux/hwmon.h>
     12#include <linux/hwmon-sysfs.h>
     13#include <linux/init.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/slab.h>
     17#include <linux/platform_device.h>
     18#include <linux/property.h>
     19
     20#include <linux/mfd/da9052/da9052.h>
     21#include <linux/mfd/da9052/reg.h>
     22#include <linux/regulator/consumer.h>
     23
     24struct da9052_hwmon {
     25	struct da9052		*da9052;
     26	struct mutex		hwmon_lock;
     27	bool			tsi_as_adc;
     28	int			tsiref_mv;
     29	struct regulator	*tsiref;
     30	struct completion	tsidone;
     31};
     32
     33static const char * const input_names[] = {
     34	[DA9052_ADC_VDDOUT]	=	"VDDOUT",
     35	[DA9052_ADC_ICH]	=	"CHARGING CURRENT",
     36	[DA9052_ADC_TBAT]	=	"BATTERY TEMP",
     37	[DA9052_ADC_VBAT]	=	"BATTERY VOLTAGE",
     38	[DA9052_ADC_IN4]	=	"ADC IN4",
     39	[DA9052_ADC_IN5]	=	"ADC IN5",
     40	[DA9052_ADC_IN6]	=	"ADC IN6",
     41	[DA9052_ADC_TSI_XP]	=	"ADC TS X+",
     42	[DA9052_ADC_TSI_YP]	=	"ADC TS Y+",
     43	[DA9052_ADC_TSI_XN]	=	"ADC TS X-",
     44	[DA9052_ADC_TSI_YN]	=	"ADC TS Y-",
     45	[DA9052_ADC_TJUNC]	=	"BATTERY JUNCTION TEMP",
     46	[DA9052_ADC_VBBAT]	=	"BACK-UP BATTERY VOLTAGE",
     47};
     48
     49/* Conversion function for VDDOUT and VBAT */
     50static inline int volt_reg_to_mv(int value)
     51{
     52	return DIV_ROUND_CLOSEST(value * 2000, 1023) + 2500;
     53}
     54
     55/* Conversion function for ADC channels 4, 5 and 6 */
     56static inline int input_reg_to_mv(int value)
     57{
     58	return DIV_ROUND_CLOSEST(value * 2500, 1023);
     59}
     60
     61/* Conversion function for VBBAT */
     62static inline int vbbat_reg_to_mv(int value)
     63{
     64	return DIV_ROUND_CLOSEST(value * 5000, 1023);
     65}
     66
     67static inline int input_tsireg_to_mv(struct da9052_hwmon *hwmon, int value)
     68{
     69	return DIV_ROUND_CLOSEST(value * hwmon->tsiref_mv, 1023);
     70}
     71
     72static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
     73{
     74	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
     75				 DA9052_ADCCONT_AUTOVDDEN,
     76				 DA9052_ADCCONT_AUTOVDDEN);
     77}
     78
     79static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
     80{
     81	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
     82				 DA9052_ADCCONT_AUTOVDDEN, 0);
     83}
     84
     85static ssize_t da9052_vddout_show(struct device *dev,
     86				  struct device_attribute *devattr, char *buf)
     87{
     88	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
     89	int ret, vdd;
     90
     91	mutex_lock(&hwmon->hwmon_lock);
     92
     93	ret = da9052_enable_vddout_channel(hwmon->da9052);
     94	if (ret < 0)
     95		goto hwmon_err;
     96
     97	vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
     98	if (vdd < 0) {
     99		ret = vdd;
    100		goto hwmon_err_release;
    101	}
    102
    103	ret = da9052_disable_vddout_channel(hwmon->da9052);
    104	if (ret < 0)
    105		goto hwmon_err;
    106
    107	mutex_unlock(&hwmon->hwmon_lock);
    108	return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
    109
    110hwmon_err_release:
    111	da9052_disable_vddout_channel(hwmon->da9052);
    112hwmon_err:
    113	mutex_unlock(&hwmon->hwmon_lock);
    114	return ret;
    115}
    116
    117static ssize_t da9052_ich_show(struct device *dev,
    118			       struct device_attribute *devattr, char *buf)
    119{
    120	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    121	int ret;
    122
    123	ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
    124	if (ret < 0)
    125		return ret;
    126
    127	/* Equivalent to 3.9mA/bit in register ICHG_AV */
    128	return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
    129}
    130
    131static ssize_t da9052_tbat_show(struct device *dev,
    132				struct device_attribute *devattr, char *buf)
    133{
    134	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    135
    136	return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
    137}
    138
    139static ssize_t da9052_vbat_show(struct device *dev,
    140				struct device_attribute *devattr, char *buf)
    141{
    142	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    143	int ret;
    144
    145	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
    146	if (ret < 0)
    147		return ret;
    148
    149	return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
    150}
    151
    152static ssize_t da9052_misc_channel_show(struct device *dev,
    153					struct device_attribute *devattr,
    154					char *buf)
    155{
    156	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    157	int channel = to_sensor_dev_attr(devattr)->index;
    158	int ret;
    159
    160	ret = da9052_adc_manual_read(hwmon->da9052, channel);
    161	if (ret < 0)
    162		return ret;
    163
    164	return sprintf(buf, "%d\n", input_reg_to_mv(ret));
    165}
    166
    167static int da9052_request_tsi_read(struct da9052_hwmon *hwmon, int channel)
    168{
    169	u8 val = DA9052_TSICONTB_TSIMAN;
    170
    171	switch (channel) {
    172	case DA9052_ADC_TSI_XP:
    173		val |= DA9052_TSICONTB_TSIMUX_XP;
    174		break;
    175	case DA9052_ADC_TSI_YP:
    176		val |= DA9052_TSICONTB_TSIMUX_YP;
    177		break;
    178	case DA9052_ADC_TSI_XN:
    179		val |= DA9052_TSICONTB_TSIMUX_XN;
    180		break;
    181	case DA9052_ADC_TSI_YN:
    182		val |= DA9052_TSICONTB_TSIMUX_YN;
    183		break;
    184	}
    185
    186	return da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_B_REG, val);
    187}
    188
    189static int da9052_get_tsi_result(struct da9052_hwmon *hwmon, int channel)
    190{
    191	u8 regs[3];
    192	int msb, lsb, err;
    193
    194	/* block read to avoid separation of MSB and LSB */
    195	err = da9052_group_read(hwmon->da9052, DA9052_TSI_X_MSB_REG,
    196				ARRAY_SIZE(regs), regs);
    197	if (err)
    198		return err;
    199
    200	switch (channel) {
    201	case DA9052_ADC_TSI_XP:
    202	case DA9052_ADC_TSI_XN:
    203		msb = regs[0] << DA9052_TSILSB_TSIXL_BITS;
    204		lsb = regs[2] & DA9052_TSILSB_TSIXL;
    205		lsb >>= DA9052_TSILSB_TSIXL_SHIFT;
    206		break;
    207	case DA9052_ADC_TSI_YP:
    208	case DA9052_ADC_TSI_YN:
    209		msb = regs[1] << DA9052_TSILSB_TSIYL_BITS;
    210		lsb = regs[2] & DA9052_TSILSB_TSIYL;
    211		lsb >>= DA9052_TSILSB_TSIYL_SHIFT;
    212		break;
    213	default:
    214		return -EINVAL;
    215	}
    216
    217	return msb | lsb;
    218}
    219
    220
    221static ssize_t __da9052_read_tsi(struct device *dev, int channel)
    222{
    223	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    224	int ret;
    225
    226	reinit_completion(&hwmon->tsidone);
    227
    228	ret = da9052_request_tsi_read(hwmon, channel);
    229	if (ret < 0)
    230		return ret;
    231
    232	/* Wait for an conversion done interrupt */
    233	if (!wait_for_completion_timeout(&hwmon->tsidone,
    234					 msecs_to_jiffies(500)))
    235		return -ETIMEDOUT;
    236
    237	return da9052_get_tsi_result(hwmon, channel);
    238}
    239
    240static ssize_t da9052_tsi_show(struct device *dev,
    241			       struct device_attribute *devattr, char *buf)
    242{
    243	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    244	int channel = to_sensor_dev_attr(devattr)->index;
    245	int ret;
    246
    247	mutex_lock(&hwmon->da9052->auxadc_lock);
    248	ret = __da9052_read_tsi(dev, channel);
    249	mutex_unlock(&hwmon->da9052->auxadc_lock);
    250
    251	if (ret < 0)
    252		return ret;
    253	else
    254		return sprintf(buf, "%d\n", input_tsireg_to_mv(hwmon, ret));
    255}
    256
    257static ssize_t da9052_tjunc_show(struct device *dev,
    258				 struct device_attribute *devattr, char *buf)
    259{
    260	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    261	int tjunc;
    262	int toffset;
    263
    264	tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
    265	if (tjunc < 0)
    266		return tjunc;
    267
    268	toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
    269	if (toffset < 0)
    270		return toffset;
    271
    272	/*
    273	 * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
    274	 * T_OFFSET is a trim value used to improve accuracy of the result
    275	 */
    276	return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
    277}
    278
    279static ssize_t da9052_vbbat_show(struct device *dev,
    280				 struct device_attribute *devattr, char *buf)
    281{
    282	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    283	int ret;
    284
    285	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
    286	if (ret < 0)
    287		return ret;
    288
    289	return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
    290}
    291
    292static ssize_t label_show(struct device *dev,
    293			  struct device_attribute *devattr, char *buf)
    294{
    295	return sprintf(buf, "%s\n",
    296		       input_names[to_sensor_dev_attr(devattr)->index]);
    297}
    298
    299static umode_t da9052_channel_is_visible(struct kobject *kobj,
    300					 struct attribute *attr, int index)
    301{
    302	struct device *dev = kobj_to_dev(kobj);
    303	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
    304	struct device_attribute *dattr = container_of(attr,
    305				struct device_attribute, attr);
    306	struct sensor_device_attribute *sattr = to_sensor_dev_attr(dattr);
    307
    308	if (!hwmon->tsi_as_adc) {
    309		switch (sattr->index) {
    310		case DA9052_ADC_TSI_XP:
    311		case DA9052_ADC_TSI_YP:
    312		case DA9052_ADC_TSI_XN:
    313		case DA9052_ADC_TSI_YN:
    314			return 0;
    315		}
    316	}
    317
    318	return attr->mode;
    319}
    320
    321static SENSOR_DEVICE_ATTR_RO(in0_input, da9052_vddout, DA9052_ADC_VDDOUT);
    322static SENSOR_DEVICE_ATTR_RO(in0_label, label, DA9052_ADC_VDDOUT);
    323static SENSOR_DEVICE_ATTR_RO(in3_input, da9052_vbat, DA9052_ADC_VBAT);
    324static SENSOR_DEVICE_ATTR_RO(in3_label, label, DA9052_ADC_VBAT);
    325static SENSOR_DEVICE_ATTR_RO(in4_input, da9052_misc_channel, DA9052_ADC_IN4);
    326static SENSOR_DEVICE_ATTR_RO(in4_label, label, DA9052_ADC_IN4);
    327static SENSOR_DEVICE_ATTR_RO(in5_input, da9052_misc_channel, DA9052_ADC_IN5);
    328static SENSOR_DEVICE_ATTR_RO(in5_label, label, DA9052_ADC_IN5);
    329static SENSOR_DEVICE_ATTR_RO(in6_input, da9052_misc_channel, DA9052_ADC_IN6);
    330static SENSOR_DEVICE_ATTR_RO(in6_label, label, DA9052_ADC_IN6);
    331static SENSOR_DEVICE_ATTR_RO(in9_input, da9052_vbbat, DA9052_ADC_VBBAT);
    332static SENSOR_DEVICE_ATTR_RO(in9_label, label, DA9052_ADC_VBBAT);
    333
    334static SENSOR_DEVICE_ATTR_RO(in70_input, da9052_tsi, DA9052_ADC_TSI_XP);
    335static SENSOR_DEVICE_ATTR_RO(in70_label, label, DA9052_ADC_TSI_XP);
    336static SENSOR_DEVICE_ATTR_RO(in71_input, da9052_tsi, DA9052_ADC_TSI_XN);
    337static SENSOR_DEVICE_ATTR_RO(in71_label, label, DA9052_ADC_TSI_XN);
    338static SENSOR_DEVICE_ATTR_RO(in72_input, da9052_tsi, DA9052_ADC_TSI_YP);
    339static SENSOR_DEVICE_ATTR_RO(in72_label, label, DA9052_ADC_TSI_YP);
    340static SENSOR_DEVICE_ATTR_RO(in73_input, da9052_tsi, DA9052_ADC_TSI_YN);
    341static SENSOR_DEVICE_ATTR_RO(in73_label, label, DA9052_ADC_TSI_YN);
    342
    343static SENSOR_DEVICE_ATTR_RO(curr1_input, da9052_ich, DA9052_ADC_ICH);
    344static SENSOR_DEVICE_ATTR_RO(curr1_label, label, DA9052_ADC_ICH);
    345
    346static SENSOR_DEVICE_ATTR_RO(temp2_input, da9052_tbat, DA9052_ADC_TBAT);
    347static SENSOR_DEVICE_ATTR_RO(temp2_label, label, DA9052_ADC_TBAT);
    348static SENSOR_DEVICE_ATTR_RO(temp8_input, da9052_tjunc, DA9052_ADC_TJUNC);
    349static SENSOR_DEVICE_ATTR_RO(temp8_label, label, DA9052_ADC_TJUNC);
    350
    351static struct attribute *da9052_attrs[] = {
    352	&sensor_dev_attr_in0_input.dev_attr.attr,
    353	&sensor_dev_attr_in0_label.dev_attr.attr,
    354	&sensor_dev_attr_in3_input.dev_attr.attr,
    355	&sensor_dev_attr_in3_label.dev_attr.attr,
    356	&sensor_dev_attr_in4_input.dev_attr.attr,
    357	&sensor_dev_attr_in4_label.dev_attr.attr,
    358	&sensor_dev_attr_in5_input.dev_attr.attr,
    359	&sensor_dev_attr_in5_label.dev_attr.attr,
    360	&sensor_dev_attr_in6_input.dev_attr.attr,
    361	&sensor_dev_attr_in6_label.dev_attr.attr,
    362	&sensor_dev_attr_in70_input.dev_attr.attr,
    363	&sensor_dev_attr_in70_label.dev_attr.attr,
    364	&sensor_dev_attr_in71_input.dev_attr.attr,
    365	&sensor_dev_attr_in71_label.dev_attr.attr,
    366	&sensor_dev_attr_in72_input.dev_attr.attr,
    367	&sensor_dev_attr_in72_label.dev_attr.attr,
    368	&sensor_dev_attr_in73_input.dev_attr.attr,
    369	&sensor_dev_attr_in73_label.dev_attr.attr,
    370	&sensor_dev_attr_in9_input.dev_attr.attr,
    371	&sensor_dev_attr_in9_label.dev_attr.attr,
    372	&sensor_dev_attr_curr1_input.dev_attr.attr,
    373	&sensor_dev_attr_curr1_label.dev_attr.attr,
    374	&sensor_dev_attr_temp2_input.dev_attr.attr,
    375	&sensor_dev_attr_temp2_label.dev_attr.attr,
    376	&sensor_dev_attr_temp8_input.dev_attr.attr,
    377	&sensor_dev_attr_temp8_label.dev_attr.attr,
    378	NULL
    379};
    380
    381static const struct attribute_group da9052_group = {
    382	.attrs = da9052_attrs,
    383	.is_visible = da9052_channel_is_visible,
    384};
    385__ATTRIBUTE_GROUPS(da9052);
    386
    387static irqreturn_t da9052_tsi_datardy_irq(int irq, void *data)
    388{
    389	struct da9052_hwmon *hwmon = data;
    390
    391	complete(&hwmon->tsidone);
    392	return IRQ_HANDLED;
    393}
    394
    395static int da9052_hwmon_probe(struct platform_device *pdev)
    396{
    397	struct device *dev = &pdev->dev;
    398	struct da9052_hwmon *hwmon;
    399	struct device *hwmon_dev;
    400	int err;
    401
    402	hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
    403	if (!hwmon)
    404		return -ENOMEM;
    405
    406	platform_set_drvdata(pdev, hwmon);
    407
    408	mutex_init(&hwmon->hwmon_lock);
    409	hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
    410
    411	init_completion(&hwmon->tsidone);
    412
    413	hwmon->tsi_as_adc =
    414		device_property_read_bool(pdev->dev.parent, "dlg,tsi-as-adc");
    415
    416	if (hwmon->tsi_as_adc) {
    417		hwmon->tsiref = devm_regulator_get(pdev->dev.parent, "tsiref");
    418		if (IS_ERR(hwmon->tsiref)) {
    419			err = PTR_ERR(hwmon->tsiref);
    420			dev_err(&pdev->dev, "failed to get tsiref: %d", err);
    421			return err;
    422		}
    423
    424		err = regulator_enable(hwmon->tsiref);
    425		if (err)
    426			return err;
    427
    428		hwmon->tsiref_mv = regulator_get_voltage(hwmon->tsiref);
    429		if (hwmon->tsiref_mv < 0) {
    430			err = hwmon->tsiref_mv;
    431			goto exit_regulator;
    432		}
    433
    434		/* convert from microvolt (DT) to millivolt (hwmon) */
    435		hwmon->tsiref_mv /= 1000;
    436
    437		/* TSIREF limits from datasheet */
    438		if (hwmon->tsiref_mv < 1800 || hwmon->tsiref_mv > 2600) {
    439			dev_err(hwmon->da9052->dev, "invalid TSIREF voltage: %d",
    440				hwmon->tsiref_mv);
    441			err = -ENXIO;
    442			goto exit_regulator;
    443		}
    444
    445		/* disable touchscreen features */
    446		da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_A_REG, 0x00);
    447
    448		/* Sample every 1ms */
    449		da9052_reg_update(hwmon->da9052, DA9052_ADC_CONT_REG,
    450					  DA9052_ADCCONT_ADCMODE,
    451					  DA9052_ADCCONT_ADCMODE);
    452
    453		err = da9052_request_irq(hwmon->da9052, DA9052_IRQ_TSIREADY,
    454					 "tsiready-irq", da9052_tsi_datardy_irq,
    455					 hwmon);
    456		if (err) {
    457			dev_err(&pdev->dev, "Failed to register TSIRDY IRQ: %d",
    458				err);
    459			goto exit_regulator;
    460		}
    461	}
    462
    463	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
    464							   hwmon,
    465							   da9052_groups);
    466	err = PTR_ERR_OR_ZERO(hwmon_dev);
    467	if (err)
    468		goto exit_irq;
    469
    470	return 0;
    471
    472exit_irq:
    473	if (hwmon->tsi_as_adc)
    474		da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
    475exit_regulator:
    476	if (hwmon->tsiref)
    477		regulator_disable(hwmon->tsiref);
    478
    479	return err;
    480}
    481
    482static int da9052_hwmon_remove(struct platform_device *pdev)
    483{
    484	struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
    485
    486	if (hwmon->tsi_as_adc) {
    487		da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
    488		regulator_disable(hwmon->tsiref);
    489	}
    490
    491	return 0;
    492}
    493
    494static struct platform_driver da9052_hwmon_driver = {
    495	.probe = da9052_hwmon_probe,
    496	.remove = da9052_hwmon_remove,
    497	.driver = {
    498		.name = "da9052-hwmon",
    499	},
    500};
    501
    502module_platform_driver(da9052_hwmon_driver);
    503
    504MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
    505MODULE_DESCRIPTION("DA9052 HWMON driver");
    506MODULE_LICENSE("GPL");
    507MODULE_ALIAS("platform:da9052-hwmon");