From 48ed8877244637b52aec0a114cdccd8ec26e66b1 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 17 Sep 2012 18:40:09 +0100 Subject: hwmon: Versatile Express hwmon driver hwmon framework driver for Versatile Express sensors, providing information about board level voltage (only when regulator driver is not configured), currents, temperature and power/energy usage. Labels for the values can be defined as DT properties. Signed-off-by: Pawel Moll Acked-by: Guenter Roeck --- drivers/hwmon/Kconfig | 8 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/vexpress.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/hwmon/vexpress.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c4633de6446..db213fe958a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1197,6 +1197,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_VEXPRESS + tristate "Versatile Express" + depends on VEXPRESS_CONFIG + help + This driver provides support for hardware sensors available on + the ARM Ltd's Versatile Express platform. It can provide wide + range of information like temperature, power, energy. + config SENSORS_VIA_CPUTEMP tristate "VIA CPU temperature sensor" depends on X86 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8d5fcb5e8e9..aac8b7c619d 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -121,6 +121,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_VEXPRESS) += vexpress.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c new file mode 100644 index 00000000000..59fd1268e58 --- /dev/null +++ b/drivers/hwmon/vexpress.c @@ -0,0 +1,229 @@ +/* + * 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) 2012 ARM Limited + */ + +#define DRVNAME "vexpress-hwmon" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +struct vexpress_hwmon_data { + struct device *hwmon_dev; + struct vexpress_config_func *func; +}; + +static ssize_t vexpress_hwmon_name_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + const char *compatible = of_get_property(dev->of_node, "compatible", + NULL); + + return sprintf(buffer, "%s\n", compatible); +} + +static ssize_t vexpress_hwmon_label_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + const char *label = of_get_property(dev->of_node, "label", NULL); + + if (!label) + return -ENOENT; + + return snprintf(buffer, PAGE_SIZE, "%s\n", label); +} + +static ssize_t vexpress_hwmon_u32_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + struct vexpress_hwmon_data *data = dev_get_drvdata(dev); + int err; + u32 value; + + err = vexpress_config_read(data->func, 0, &value); + if (err) + return err; + + return snprintf(buffer, PAGE_SIZE, "%u\n", value / + to_sensor_dev_attr(dev_attr)->index); +} + +static ssize_t vexpress_hwmon_u64_show(struct device *dev, + struct device_attribute *dev_attr, char *buffer) +{ + struct vexpress_hwmon_data *data = dev_get_drvdata(dev); + int err; + u32 value_hi, value_lo; + + err = vexpress_config_read(data->func, 0, &value_lo); + if (err) + return err; + + err = vexpress_config_read(data->func, 1, &value_hi); + if (err) + return err; + + return snprintf(buffer, PAGE_SIZE, "%llu\n", + div_u64(((u64)value_hi << 32) | value_lo, + to_sensor_dev_attr(dev_attr)->index)); +} + +static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL); + +#define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr) \ +struct attribute *vexpress_hwmon_attrs_##_name[] = { \ + &dev_attr_name.attr, \ + &dev_attr_##_label_attr.attr, \ + &sensor_dev_attr_##_input_attr.dev_attr.attr, \ + NULL \ +} + +#if !defined(CONFIG_REGULATOR_VEXPRESS) +static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1000); +static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input); +static struct attribute_group vexpress_hwmon_group_volt = { + .attrs = vexpress_hwmon_attrs_volt, +}; +#endif + +static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1000); +static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input); +static struct attribute_group vexpress_hwmon_group_amp = { + .attrs = vexpress_hwmon_attrs_amp, +}; + +static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1000); +static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input); +static struct attribute_group vexpress_hwmon_group_temp = { + .attrs = vexpress_hwmon_attrs_temp, +}; + +static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show, + NULL, 1); +static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input); +static struct attribute_group vexpress_hwmon_group_power = { + .attrs = vexpress_hwmon_attrs_power, +}; + +static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); +static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show, + NULL, 1); +static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input); +static struct attribute_group vexpress_hwmon_group_energy = { + .attrs = vexpress_hwmon_attrs_energy, +}; + +static struct of_device_id vexpress_hwmon_of_match[] = { +#if !defined(CONFIG_REGULATOR_VEXPRESS) + { + .compatible = "arm,vexpress-volt", + .data = &vexpress_hwmon_group_volt, + }, +#endif + { + .compatible = "arm,vexpress-amp", + .data = &vexpress_hwmon_group_amp, + }, { + .compatible = "arm,vexpress-temp", + .data = &vexpress_hwmon_group_temp, + }, { + .compatible = "arm,vexpress-power", + .data = &vexpress_hwmon_group_power, + }, { + .compatible = "arm,vexpress-energy", + .data = &vexpress_hwmon_group_energy, + }, + {} +}; +MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match); + +static int vexpress_hwmon_probe(struct platform_device *pdev) +{ + int err; + const struct of_device_id *match; + struct vexpress_hwmon_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + platform_set_drvdata(pdev, data); + + match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); + if (!match) + return -ENODEV; + + data->func = vexpress_config_func_get_by_dev(&pdev->dev); + if (!data->func) + return -ENODEV; + + err = sysfs_create_group(&pdev->dev.kobj, match->data); + if (err) + goto error; + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto error; + } + + return 0; + +error: + sysfs_remove_group(&pdev->dev.kobj, match->data); + vexpress_config_func_put(data->func); + return err; +} + +static int __devexit vexpress_hwmon_remove(struct platform_device *pdev) +{ + struct vexpress_hwmon_data *data = platform_get_drvdata(pdev); + const struct of_device_id *match; + + hwmon_device_unregister(data->hwmon_dev); + + match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); + sysfs_remove_group(&pdev->dev.kobj, match->data); + + vexpress_config_func_put(data->func); + + return 0; +} + +static struct platform_driver vexpress_hwmon_driver = { + .probe = vexpress_hwmon_probe, + .remove = __devexit_p(vexpress_hwmon_remove), + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = vexpress_hwmon_of_match, + }, +}; + +module_platform_driver(vexpress_hwmon_driver); + +MODULE_AUTHOR("Pawel Moll "); +MODULE_DESCRIPTION("Versatile Express hwmon sensors driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:vexpress-hwmon"); -- cgit v1.2.3-70-g09d2 From 2b88ff4a75f2175902389e3356d6227d7030e382 Mon Sep 17 00:00:00 2001 From: Eunki Kim Date: Tue, 23 Oct 2012 22:39:38 +0900 Subject: gpio: samsung: Fix input mode setting function for GPIO int This patch makes GPIO pin to INTERRUPT mode or INPUT mode according to bitmap_gpio_int. When the related bit of bitmap_gpio_int is set, it makes GPIO pin to INTERRUPT mode instrad of INPUT mode in the samsung_gpiolib_4bit_input function. Signed-off-by: Eunki Kim Acked-by: Linus Walleij Signed-off-by: Kukjin Kim --- drivers/gpio/gpio-samsung.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index a006f0db15a..15be3d9aebe 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -596,7 +596,10 @@ static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, unsigned long con; con = __raw_readl(base + GPIOCON_OFF); - con &= ~(0xf << con_4bit_shift(offset)); + if (ourchip->bitmap_gpio_int & BIT(offset)) + con |= 0xf << con_4bit_shift(offset); + else + con &= ~(0xf << con_4bit_shift(offset)); __raw_writel(con, base + GPIOCON_OFF); gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); @@ -1081,6 +1084,8 @@ static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip if ((base != NULL) && (chip->base == NULL)) chip->base = base + ((i) * 0x20); + chip->bitmap_gpio_int = 0; + samsung_gpiolib_add(chip); } } -- cgit v1.2.3-70-g09d2 From 343db4bda61feb3ac177d73f006e3527dcb431da Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 23 Oct 2012 23:12:23 +0900 Subject: gpio: samsung: use pr_* instead of printk This patch uses pr_* instead of printk. Also, gpio_dbg is replaced with pr_debug. Signed-off-by: Jingoo Han Acked-by/Reviewed-by: Linus Walleij Signed-off-by: Kukjin Kim --- drivers/gpio/gpio-samsung.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 15be3d9aebe..43c4595b5cf 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -42,12 +42,6 @@ #include #include -#ifndef DEBUG_GPIO -#define gpio_dbg(x...) do { } while (0) -#else -#define gpio_dbg(x...) printk(KERN_DEBUG x) -#endif - int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, unsigned int off, samsung_gpio_pull_t pull) { @@ -602,7 +596,7 @@ static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, con &= ~(0xf << con_4bit_shift(offset)); __raw_writel(con, base + GPIOCON_OFF); - gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); + pr_debug("%s: %p: CON now %08lx\n", __func__, base, con); return 0; } @@ -630,7 +624,7 @@ static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, __raw_writel(con, base + GPIOCON_OFF); __raw_writel(dat, base + GPIODAT_OFF); - gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); return 0; } @@ -674,7 +668,7 @@ static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, con &= ~(0xf << con_4bit_shift(offset)); __raw_writel(con, regcon); - gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con); + pr_debug("%s: %p: CON %08lx\n", __func__, base, con); return 0; } @@ -709,7 +703,7 @@ static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, __raw_writel(con, regcon); __raw_writel(dat, base + GPIODAT_OFF); - gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); return 0; } @@ -929,10 +923,10 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) #ifdef CONFIG_PM if (chip->pm != NULL) { if (!chip->pm->save || !chip->pm->resume) - printk(KERN_ERR "gpio: %s has missing PM functions\n", + pr_err("gpio: %s has missing PM functions\n", gc->label); } else - printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); + pr_err("gpio: %s has no PM function\n", gc->label); #endif /* gpiochip_add() prints own failure message on error. */ -- cgit v1.2.3-70-g09d2