diff options
author | Jon Medhurst <tixy@linaro.org> | 2015-04-22 18:17:30 +0100 |
---|---|---|
committer | Jon Medhurst <tixy@linaro.org> | 2015-04-22 18:17:30 +0100 |
commit | 9a5e38d6ac13ac05aad9dd215c68bcce54fa1f7c (patch) | |
tree | 47b6d20abc46ad4f0a4b55ba061d80fa52410ebb /drivers | |
parent | c63a5aa52b242bb92440b0bc546e7097b40eed4a (diff) | |
parent | deb7033a0bfb9568ee455b154bcedd0669b2162e (diff) |
Merge branch 'lsk-3.10-armlt-juno-misc' into integration-lsk-3.10-juno-android-new
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 7 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 8 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/v2m-juno.c | 388 |
4 files changed, 402 insertions, 2 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 67bbbd8ae507..31a704cca182 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -668,11 +668,13 @@ CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); static void __init arch_timer_mem_init(struct device_node *np) { struct device_node *frame, *best_frame = NULL; - void __iomem *cntctlbase, *base; + /*void __iomem *cntctlbase;*/ + void __iomem *base; unsigned int irq; u32 cnttidr; arch_timers_present |= ARCH_MEM_TIMER; + /* cntctlbase = of_iomap(np, 0); if (!cntctlbase) { pr_err("arch_timer: Can't find CNTCTLBase\n"); @@ -681,7 +683,8 @@ static void __init arch_timer_mem_init(struct device_node *np) cnttidr = readl_relaxed(cntctlbase + CNTTIDR); iounmap(cntctlbase); - + */ + cnttidr = 0x1; /* * Try to find a virtual capable frame. Otherwise fall back to a * physical capable frame. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f25f29835b3e..1d465264a05f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1296,6 +1296,14 @@ config SENSORS_TWL4030_MADC This driver can also be built as a module. If so it will be called twl4030-madc-hwmon. +config SENSORS_V2M_JUNO + tristate "V2M Juno" + depends on VEXPRESS_CONFIG + help + This driver provides support for hardware sensors available on + the ARM Ltd's V2M Juno platform. It can provide wide + range of information like current, voltage, power, energy. + config SENSORS_VEXPRESS tristate "Versatile Express" depends on VEXPRESS_CONFIG diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index d17d3e64f9f4..72e23b5cdf1c 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_SENSORS_TMP102) += tmp102.o obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o +obj-$(CONFIG_SENSORS_V2M_JUNO) += v2m-juno.o obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o diff --git a/drivers/hwmon/v2m-juno.c b/drivers/hwmon/v2m-juno.c new file mode 100644 index 000000000000..1ce2b728779a --- /dev/null +++ b/drivers/hwmon/v2m-juno.c @@ -0,0 +1,388 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2014 ARM Limited + */ + +#define DRVNAME "v2m-juno-hwmon" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +struct v2m_juno_hwmon_type { + const char *name; + const struct attribute_group *attr_groups; +}; + +static void __iomem *base; + +struct v2m_juno_hwmon_dev { + struct v2m_juno_hwmon_type *type; + struct device *hwmon_dev; + const char *name; + u32 offset; + u32 mult; + u32 div; +}; + +static ssize_t v2m_juno_hwmon_name_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + struct v2m_juno_hwmon_dev *hdev = dev_get_drvdata(dev); + + return sprintf(buffer, "%s\n", hdev->name); +} + +static ssize_t v2m_juno_hwmon_u32_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + struct v2m_juno_hwmon_dev *hdev = dev_get_drvdata(dev); + u64 value; + + value = readl(base + hdev->offset); + value *= hdev->mult; + return snprintf(buffer, PAGE_SIZE, "%llu\n", value / hdev->div); +} + +static ssize_t v2m_juno_hwmon_u64_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + struct v2m_juno_hwmon_dev *hdev = dev_get_drvdata(dev); + u64 value; + + value = readq(base + hdev->offset); + value *= hdev->mult; + return snprintf(buffer, PAGE_SIZE, "%llu\n", value / hdev->div); +} + +static DEVICE_ATTR(name, S_IRUGO, v2m_juno_hwmon_name_show, NULL); + +#define JUNO_HWMON_ATTRS(_name, _input_attr) \ +struct attribute *v2m_juno_hwmon_attrs_##_name[] = { \ + &dev_attr_name.attr, \ + &sensor_dev_attr_##_input_attr.dev_attr.attr, \ + NULL \ +} + +#if !defined(CONFIG_REGULATOR_VEXPRESS) +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, v2m_juno_hwmon_u32_show, + NULL, 1); +static JUNO_HWMON_ATTRS(volt, in1_input); +static struct attribute_group v2m_juno_hwmon_group_volt = { + .attrs = v2m_juno_hwmon_attrs_volt, +}; +static struct v2m_juno_hwmon_type v2m_juno_hwmon_volt = { + .name = "v2m_juno_volt", + .attr_groups = &v2m_juno_hwmon_group_volt, +}; +#endif + +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, v2m_juno_hwmon_u32_show, + NULL, 1); +static JUNO_HWMON_ATTRS(amp, curr1_input); +static struct attribute_group v2m_juno_hwmon_group_amp = { + .attrs = v2m_juno_hwmon_attrs_amp, +}; +static struct v2m_juno_hwmon_type v2m_juno_hwmon_amp = { + .name = "v2m_juno_amp", + .attr_groups = &v2m_juno_hwmon_group_amp, +}; + +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, v2m_juno_hwmon_u32_show, + NULL, 1); +static JUNO_HWMON_ATTRS(power, power1_input); +static struct attribute_group v2m_juno_hwmon_group_power = { + .attrs = v2m_juno_hwmon_attrs_power, +}; +static struct v2m_juno_hwmon_type v2m_juno_hwmon_power = { + .name = "v2m_juno_power", + .attr_groups = &v2m_juno_hwmon_group_power, +}; + +static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, v2m_juno_hwmon_u64_show, + NULL, 1); +static JUNO_HWMON_ATTRS(energy, energy1_input); +static struct attribute_group v2m_juno_hwmon_group_energy = { + .attrs = v2m_juno_hwmon_attrs_energy, +}; +static struct v2m_juno_hwmon_type v2m_juno_hwmon_energy = { + .name = "v2m_juno_energy", + .attr_groups = &v2m_juno_hwmon_group_energy, +}; + +/* current adc channels */ +#define SYS_ADC_CH0_PM1_SYS 0xd0 +#define SYS_ADC_CH1_PM2_A57 0xd4 +#define SYS_ADC_CH2_PM3_A53 0xd8 +#define SYS_ADC_CH3_PM4_GPU 0xdc + +/* voltage adc channels */ +#define SYS_ADC_CH4_VSYS 0xe0 +#define SYS_ADC_CH5_VA57 0xe4 +#define SYS_ADC_CH6_VA53 0xe8 +#define SYS_ADC_CH7_VGPU 0xec + +/* power adc channels */ +#define SYS_EN_CH04_SYS 0xf0 +#define SYS_EN_CH15_A57 0xf4 +#define SYS_EN_CH26_A53 0xf8 +#define SYS_EN_CH37_GPU 0xfc + +/* energy adc channels */ +#define SYS_ENM_CH0_L_SYS 0x100 +#define SYS_ENM_CH0_H_SYS 0x104 +#define SYS_ENM_CH1_L_A57 0x108 +#define SYS_ENM_CH1_H_A57 0x10c +#define SYS_ENM_CH0_L_A53 0x110 +#define SYS_ENM_CH0_H_A53 0x114 +#define SYS_ENM_CH0_L_GPU 0x118 +#define SYS_ENM_CH0_H_GPU 0x11c + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_curr_sys = { + .type = &v2m_juno_hwmon_amp, + .offset = SYS_ADC_CH0_PM1_SYS, + .name = "sys_curr", + .mult = 1000, + .div = 761 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_curr_a57 = { + .type = &v2m_juno_hwmon_amp, + .offset = SYS_ADC_CH1_PM2_A57, + .name = "a57_curr", + .mult = 1000, + .div = 381, +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_curr_a53 = { + .type = &v2m_juno_hwmon_amp, + .offset = SYS_ADC_CH2_PM3_A53, + .name = "a53_curr", + .mult = 1000, + .div = 761 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_curr_gpu = { + .type = &v2m_juno_hwmon_amp, + .offset = SYS_ADC_CH3_PM4_GPU, + .name = "gpu_curr", + .mult = 1000, + .div = 381 +}; + +#if !defined(CONFIG_REGULATOR_VEXPRESS) +struct v2m_juno_hwmon_dev v2m_juno_hwmon_volt_sys = { + .type = &v2m_juno_hwmon_volt, + .offset = SYS_ADC_CH4_VSYS, + .name = "sys_volt", + .mult = 1000, + .div = 1622 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_volt_a57 = { + .type = &v2m_juno_hwmon_volt, + .offset = SYS_ADC_CH5_VA57, + .name = "a57_volt", + .mult = 1000, + .div = 1622 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_volt_a53 = { + .type = &v2m_juno_hwmon_volt, + .offset = SYS_ADC_CH6_VA53, + .name = "a53_volt", + .mult = 1000, + .div = 1622 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_volt_gpu = { + .type = &v2m_juno_hwmon_volt, + .offset = SYS_ADC_CH7_VGPU, + .name = "gpu_volt", + .mult = 1000, + .div = 1622 +}; +#endif + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_power_sys = { + .type = &v2m_juno_hwmon_power, + .offset = SYS_EN_CH04_SYS, + .name = "sys_power", + .mult = 1000, + .div = 1234803 + +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_power_a57 = { + .type = &v2m_juno_hwmon_power, + .offset = SYS_EN_CH15_A57, + .name = "a57_power", + .mult = 1000, + .div = 617402 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_power_a53 = { + .type = &v2m_juno_hwmon_power, + .offset = SYS_EN_CH26_A53, + .name = "a53_power", + .mult = 1000, + .div = 1234803, +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_power_gpu = { + .type = &v2m_juno_hwmon_power, + .offset = SYS_EN_CH37_GPU, + .mult = 1000, + .name = "gpu_power", + .div = 617402 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_energy_sys = { + .type = &v2m_juno_hwmon_energy, + .offset = SYS_ENM_CH0_L_SYS, + .name = "sys_energy", + .mult = 100, + .div = 1234803, +}; +struct v2m_juno_hwmon_dev v2m_juno_hwmon_energy_a57 = { + .type = &v2m_juno_hwmon_energy, + .offset = SYS_ENM_CH1_L_A57, + .name = "a57_energy", + .mult = 100, + .div = 617402 +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_energy_a53 = { + .type = &v2m_juno_hwmon_energy, + .offset = SYS_ENM_CH0_L_A53, + .name = "a53_energy", + .mult = 100, + .div = 1234803, +}; + +struct v2m_juno_hwmon_dev v2m_juno_hwmon_energy_gpu = { + .type = &v2m_juno_hwmon_energy, + .offset = SYS_ENM_CH0_L_GPU, + .name = "gpu_energy", + .mult = 100, + .div = 617402 +}; + +static struct v2m_juno_hwmon_dev *v2m_juno_hwmon_devices[] = { +#if !defined(CONFIG_REGULATOR_VEXPRESS) + &v2m_juno_hwmon_volt_sys, + &v2m_juno_hwmon_volt_a57, + &v2m_juno_hwmon_volt_a53, + &v2m_juno_hwmon_volt_gpu, +#endif + &v2m_juno_hwmon_energy_sys, + &v2m_juno_hwmon_energy_a57, + &v2m_juno_hwmon_energy_a53, + &v2m_juno_hwmon_energy_gpu, + &v2m_juno_hwmon_power_sys, + &v2m_juno_hwmon_power_a57, + &v2m_juno_hwmon_power_a53, + &v2m_juno_hwmon_power_gpu, + &v2m_juno_hwmon_curr_sys, + &v2m_juno_hwmon_curr_a57, + &v2m_juno_hwmon_curr_a53, + &v2m_juno_hwmon_curr_gpu, +}; + +static struct of_device_id v2m_juno_hwmon_of_match[] = { + { + .compatible = "arm,v2m-juno-meters", + }, + {} +}; +MODULE_DEVICE_TABLE(of, v2m_juno_hwmon_of_match); + +static int v2m_juno_hwmon_probe(struct platform_device *pdev) +{ + int i, err; + const struct of_device_id *match; + struct v2m_juno_hwmon_dev *dev; + struct resource *mem; + + match = of_match_device(v2m_juno_hwmon_of_match, &pdev->dev); + if (!match) + return -ENODEV; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, mem); + + for (i = 0; i < ARRAY_SIZE(v2m_juno_hwmon_devices); i++) { + dev = v2m_juno_hwmon_devices[i]; + dev->hwmon_dev = hwmon_device_register(&pdev->dev); + + if (IS_ERR(dev->hwmon_dev)) { + err = PTR_ERR(dev->hwmon_dev); + goto error; + } + err = sysfs_create_group(&dev->hwmon_dev->kobj, + dev->type->attr_groups); + if (err) + goto error_sysfs; + + dev_set_drvdata(dev->hwmon_dev, dev); + } + + return 0; + +error: + while (--i >= 0) { + dev = v2m_juno_hwmon_devices[i]; + sysfs_remove_group(&dev->hwmon_dev->kobj, + dev->type->attr_groups); +error_sysfs: + hwmon_device_unregister(dev->hwmon_dev); + } + + return err; +} + +static int v2m_juno_hwmon_remove(struct platform_device *pdev) +{ + int i; + struct v2m_juno_hwmon_dev *dev; + + for (i = 0; i < ARRAY_SIZE(v2m_juno_hwmon_devices); i++) { + dev = v2m_juno_hwmon_devices[i]; + hwmon_device_unregister(dev->hwmon_dev); + sysfs_remove_group(&dev->hwmon_dev->kobj, + dev->type->attr_groups); + } + + return 0; +} + +static struct platform_driver v2m_juno_hwmon_driver = { + .probe = v2m_juno_hwmon_probe, + .remove = v2m_juno_hwmon_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = v2m_juno_hwmon_of_match, + }, +}; + +module_platform_driver(v2m_juno_hwmon_driver); + +MODULE_AUTHOR("Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>"); +MODULE_DESCRIPTION("V2M Juno hwmon sensors driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:v2m-juno-hwmon"); |