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

mc13783-adc.c (8968B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
      4 *
      5 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
      6 * Copyright (C) 2009 Sascha Hauer, Pengutronix
      7 */
      8
      9#include <linux/mfd/mc13xxx.h>
     10#include <linux/platform_device.h>
     11#include <linux/hwmon-sysfs.h>
     12#include <linux/kernel.h>
     13#include <linux/module.h>
     14#include <linux/mod_devicetable.h>
     15#include <linux/hwmon.h>
     16#include <linux/slab.h>
     17#include <linux/init.h>
     18#include <linux/err.h>
     19
     20#define DRIVER_NAME	"mc13783-adc"
     21
     22/* platform device id driver data */
     23#define MC13783_ADC_16CHANS	1
     24#define MC13783_ADC_BPDIV2	2
     25
     26struct mc13783_adc_priv {
     27	struct mc13xxx *mc13xxx;
     28	struct device *hwmon_dev;
     29	char name[PLATFORM_NAME_SIZE];
     30};
     31
     32static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
     33			 char *buf)
     34{
     35	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
     36
     37	return sprintf(buf, "%s\n", priv->name);
     38}
     39
     40static int mc13783_adc_read(struct device *dev,
     41		struct device_attribute *devattr, unsigned int *val)
     42{
     43	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
     44	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
     45	unsigned int channel = attr->index;
     46	unsigned int sample[4];
     47	int ret;
     48
     49	ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
     50			MC13XXX_ADC_MODE_MULT_CHAN,
     51			channel, 0, 0, sample);
     52	if (ret)
     53		return ret;
     54
     55	/* ADIN7 subchannels */
     56	if (channel >= 16)
     57		channel = 7;
     58
     59	channel &= 0x7;
     60
     61	*val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
     62
     63	return 0;
     64}
     65
     66static ssize_t mc13783_adc_bp_show(struct device *dev,
     67				   struct device_attribute *devattr,
     68				   char *buf)
     69{
     70	unsigned val;
     71	struct platform_device *pdev = to_platform_device(dev);
     72	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
     73	int ret = mc13783_adc_read(dev, devattr, &val);
     74
     75	if (ret)
     76		return ret;
     77
     78	if (driver_data & MC13783_ADC_BPDIV2)
     79		val = DIV_ROUND_CLOSEST(val * 9, 2);
     80	else
     81		/*
     82		 * BP (channel 2) reports with offset 2.4V to the actual value
     83		 * to fit the input range of the ADC.  unit = 2.25mV = 9/4 mV.
     84		 */
     85		val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
     86
     87	return sprintf(buf, "%u\n", val);
     88}
     89
     90static ssize_t mc13783_adc_gp_show(struct device *dev,
     91				   struct device_attribute *devattr,
     92				   char *buf)
     93{
     94	unsigned val;
     95	int ret = mc13783_adc_read(dev, devattr, &val);
     96
     97	if (ret)
     98		return ret;
     99
    100	/*
    101	 * input range is [0, 2.3V], val has 10 bits, so each bit
    102	 * is worth 9/4 mV.
    103	 */
    104	val = DIV_ROUND_CLOSEST(val * 9, 4);
    105
    106	return sprintf(buf, "%u\n", val);
    107}
    108
    109static ssize_t mc13783_adc_uid_show(struct device *dev,
    110				    struct device_attribute *devattr,
    111				    char *buf)
    112{
    113	unsigned int val;
    114	struct platform_device *pdev = to_platform_device(dev);
    115	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
    116	int ret = mc13783_adc_read(dev, devattr, &val);
    117
    118	if (ret)
    119		return ret;
    120
    121	if (driver_data & MC13783_ADC_BPDIV2)
    122		/* MC13892 have 1/2 divider, input range is [0, 4.800V] */
    123		val = DIV_ROUND_CLOSEST(val * 4800, 1024);
    124	else
    125		/* MC13783 have 0.9 divider, input range is [0, 2.555V] */
    126		val = DIV_ROUND_CLOSEST(val * 2555, 1024);
    127
    128	return sprintf(buf, "%u\n", val);
    129}
    130
    131static ssize_t mc13783_adc_temp_show(struct device *dev,
    132				     struct device_attribute *devattr,
    133				     char *buf)
    134{
    135	unsigned int val;
    136	struct platform_device *pdev = to_platform_device(dev);
    137	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
    138	int ret = mc13783_adc_read(dev, devattr, &val);
    139
    140	if (ret)
    141		return ret;
    142
    143	if (driver_data & MC13783_ADC_BPDIV2) {
    144		/*
    145		 * MC13892:
    146		 * Die Temperature Read Out Code at 25C 680
    147		 * Temperature change per LSB +0.4244C
    148		 */
    149		ret = DIV_ROUND_CLOSEST(-2635920 + val * 4244, 10);
    150	} else {
    151		/*
    152		 * MC13783:
    153		 * Die Temperature Read Out Code at 25C 282
    154		 * Temperature change per LSB -1.14C
    155		 */
    156		ret = 346480 - 1140 * val;
    157	}
    158
    159	return sprintf(buf, "%d\n", ret);
    160}
    161
    162static DEVICE_ATTR_RO(name);
    163static SENSOR_DEVICE_ATTR_RO(in2_input, mc13783_adc_bp, 2);
    164static SENSOR_DEVICE_ATTR_RO(in5_input, mc13783_adc_gp, 5);
    165static SENSOR_DEVICE_ATTR_RO(in6_input, mc13783_adc_gp, 6);
    166static SENSOR_DEVICE_ATTR_RO(in7_input, mc13783_adc_gp, 7);
    167static SENSOR_DEVICE_ATTR_RO(in8_input, mc13783_adc_gp, 8);
    168static SENSOR_DEVICE_ATTR_RO(in9_input, mc13783_adc_gp, 9);
    169static SENSOR_DEVICE_ATTR_RO(in10_input, mc13783_adc_gp, 10);
    170static SENSOR_DEVICE_ATTR_RO(in11_input, mc13783_adc_gp, 11);
    171static SENSOR_DEVICE_ATTR_RO(in12_input, mc13783_adc_gp, 12);
    172static SENSOR_DEVICE_ATTR_RO(in13_input, mc13783_adc_gp, 13);
    173static SENSOR_DEVICE_ATTR_RO(in14_input, mc13783_adc_gp, 14);
    174static SENSOR_DEVICE_ATTR_RO(in15_input, mc13783_adc_gp, 15);
    175static SENSOR_DEVICE_ATTR_RO(in16_input, mc13783_adc_uid, 16);
    176static SENSOR_DEVICE_ATTR_RO(temp1_input, mc13783_adc_temp, 17);
    177
    178static struct attribute *mc13783_attr_base[] = {
    179	&dev_attr_name.attr,
    180	&sensor_dev_attr_in2_input.dev_attr.attr,
    181	&sensor_dev_attr_in5_input.dev_attr.attr,
    182	&sensor_dev_attr_in6_input.dev_attr.attr,
    183	&sensor_dev_attr_in7_input.dev_attr.attr,
    184	&sensor_dev_attr_in16_input.dev_attr.attr,
    185	&sensor_dev_attr_temp1_input.dev_attr.attr,
    186	NULL
    187};
    188
    189static const struct attribute_group mc13783_group_base = {
    190	.attrs = mc13783_attr_base,
    191};
    192
    193/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
    194static struct attribute *mc13783_attr_16chans[] = {
    195	&sensor_dev_attr_in8_input.dev_attr.attr,
    196	&sensor_dev_attr_in9_input.dev_attr.attr,
    197	&sensor_dev_attr_in10_input.dev_attr.attr,
    198	&sensor_dev_attr_in11_input.dev_attr.attr,
    199	NULL
    200};
    201
    202static const struct attribute_group mc13783_group_16chans = {
    203	.attrs = mc13783_attr_16chans,
    204};
    205
    206/* last four channels may be occupied by the touchscreen */
    207static struct attribute *mc13783_attr_ts[] = {
    208	&sensor_dev_attr_in12_input.dev_attr.attr,
    209	&sensor_dev_attr_in13_input.dev_attr.attr,
    210	&sensor_dev_attr_in14_input.dev_attr.attr,
    211	&sensor_dev_attr_in15_input.dev_attr.attr,
    212	NULL
    213};
    214
    215static const struct attribute_group mc13783_group_ts = {
    216	.attrs = mc13783_attr_ts,
    217};
    218
    219static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
    220{
    221	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
    222	unsigned flags = mc13xxx_get_flags(priv->mc13xxx);
    223
    224	return flags & MC13XXX_USE_TOUCHSCREEN;
    225}
    226
    227static int __init mc13783_adc_probe(struct platform_device *pdev)
    228{
    229	struct mc13783_adc_priv *priv;
    230	int ret;
    231	const struct platform_device_id *id = platform_get_device_id(pdev);
    232	char *dash;
    233
    234	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    235	if (!priv)
    236		return -ENOMEM;
    237
    238	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
    239	snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
    240	dash = strchr(priv->name, '-');
    241	if (dash)
    242		*dash = '\0';
    243
    244	platform_set_drvdata(pdev, priv);
    245
    246	/* Register sysfs hooks */
    247	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
    248	if (ret)
    249		return ret;
    250
    251	if (id->driver_data & MC13783_ADC_16CHANS) {
    252		ret = sysfs_create_group(&pdev->dev.kobj,
    253				&mc13783_group_16chans);
    254		if (ret)
    255			goto out_err_create_16chans;
    256	}
    257
    258	if (!mc13783_adc_use_touchscreen(pdev)) {
    259		ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
    260		if (ret)
    261			goto out_err_create_ts;
    262	}
    263
    264	priv->hwmon_dev = hwmon_device_register(&pdev->dev);
    265	if (IS_ERR(priv->hwmon_dev)) {
    266		ret = PTR_ERR(priv->hwmon_dev);
    267		dev_err(&pdev->dev,
    268				"hwmon_device_register failed with %d.\n", ret);
    269		goto out_err_register;
    270	}
    271
    272	return 0;
    273
    274out_err_register:
    275
    276	if (!mc13783_adc_use_touchscreen(pdev))
    277		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
    278out_err_create_ts:
    279
    280	if (id->driver_data & MC13783_ADC_16CHANS)
    281		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
    282out_err_create_16chans:
    283
    284	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
    285	return ret;
    286}
    287
    288static int mc13783_adc_remove(struct platform_device *pdev)
    289{
    290	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
    291	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
    292
    293	hwmon_device_unregister(priv->hwmon_dev);
    294
    295	if (!mc13783_adc_use_touchscreen(pdev))
    296		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
    297
    298	if (driver_data & MC13783_ADC_16CHANS)
    299		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
    300
    301	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
    302
    303	return 0;
    304}
    305
    306static const struct platform_device_id mc13783_adc_idtable[] = {
    307	{
    308		.name = "mc13783-adc",
    309		.driver_data = MC13783_ADC_16CHANS,
    310	}, {
    311		.name = "mc13892-adc",
    312		.driver_data = MC13783_ADC_BPDIV2,
    313	}, {
    314		/* sentinel */
    315	}
    316};
    317MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
    318
    319static struct platform_driver mc13783_adc_driver = {
    320	.remove		= mc13783_adc_remove,
    321	.driver		= {
    322		.name	= DRIVER_NAME,
    323	},
    324	.id_table	= mc13783_adc_idtable,
    325};
    326
    327module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
    328
    329MODULE_DESCRIPTION("MC13783 ADC driver");
    330MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
    331MODULE_LICENSE("GPL");