diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/gpio-samsung.c | 25 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 8 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/vexpress.c | 229 |
4 files changed, 250 insertions, 13 deletions
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 88f41e51565..01f7fe95559 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c | |||
@@ -42,12 +42,6 @@ | |||
42 | #include <plat/gpio-fns.h> | 42 | #include <plat/gpio-fns.h> |
43 | #include <plat/pm.h> | 43 | #include <plat/pm.h> |
44 | 44 | ||
45 | #ifndef DEBUG_GPIO | ||
46 | #define gpio_dbg(x...) do { } while (0) | ||
47 | #else | ||
48 | #define gpio_dbg(x...) printk(KERN_DEBUG x) | ||
49 | #endif | ||
50 | |||
51 | int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, | 45 | int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, |
52 | unsigned int off, samsung_gpio_pull_t pull) | 46 | unsigned int off, samsung_gpio_pull_t pull) |
53 | { | 47 | { |
@@ -596,10 +590,13 @@ static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, | |||
596 | unsigned long con; | 590 | unsigned long con; |
597 | 591 | ||
598 | con = __raw_readl(base + GPIOCON_OFF); | 592 | con = __raw_readl(base + GPIOCON_OFF); |
599 | con &= ~(0xf << con_4bit_shift(offset)); | 593 | if (ourchip->bitmap_gpio_int & BIT(offset)) |
594 | con |= 0xf << con_4bit_shift(offset); | ||
595 | else | ||
596 | con &= ~(0xf << con_4bit_shift(offset)); | ||
600 | __raw_writel(con, base + GPIOCON_OFF); | 597 | __raw_writel(con, base + GPIOCON_OFF); |
601 | 598 | ||
602 | gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); | 599 | pr_debug("%s: %p: CON now %08lx\n", __func__, base, con); |
603 | 600 | ||
604 | return 0; | 601 | return 0; |
605 | } | 602 | } |
@@ -627,7 +624,7 @@ static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, | |||
627 | __raw_writel(con, base + GPIOCON_OFF); | 624 | __raw_writel(con, base + GPIOCON_OFF); |
628 | __raw_writel(dat, base + GPIODAT_OFF); | 625 | __raw_writel(dat, base + GPIODAT_OFF); |
629 | 626 | ||
630 | gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); | 627 | pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); |
631 | 628 | ||
632 | return 0; | 629 | return 0; |
633 | } | 630 | } |
@@ -671,7 +668,7 @@ static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, | |||
671 | con &= ~(0xf << con_4bit_shift(offset)); | 668 | con &= ~(0xf << con_4bit_shift(offset)); |
672 | __raw_writel(con, regcon); | 669 | __raw_writel(con, regcon); |
673 | 670 | ||
674 | gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con); | 671 | pr_debug("%s: %p: CON %08lx\n", __func__, base, con); |
675 | 672 | ||
676 | return 0; | 673 | return 0; |
677 | } | 674 | } |
@@ -706,7 +703,7 @@ static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, | |||
706 | __raw_writel(con, regcon); | 703 | __raw_writel(con, regcon); |
707 | __raw_writel(dat, base + GPIODAT_OFF); | 704 | __raw_writel(dat, base + GPIODAT_OFF); |
708 | 705 | ||
709 | gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); | 706 | pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); |
710 | 707 | ||
711 | return 0; | 708 | return 0; |
712 | } | 709 | } |
@@ -926,10 +923,10 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) | |||
926 | #ifdef CONFIG_PM | 923 | #ifdef CONFIG_PM |
927 | if (chip->pm != NULL) { | 924 | if (chip->pm != NULL) { |
928 | if (!chip->pm->save || !chip->pm->resume) | 925 | if (!chip->pm->save || !chip->pm->resume) |
929 | printk(KERN_ERR "gpio: %s has missing PM functions\n", | 926 | pr_err("gpio: %s has missing PM functions\n", |
930 | gc->label); | 927 | gc->label); |
931 | } else | 928 | } else |
932 | printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); | 929 | pr_err("gpio: %s has no PM function\n", gc->label); |
933 | #endif | 930 | #endif |
934 | 931 | ||
935 | /* gpiochip_add() prints own failure message on error. */ | 932 | /* gpiochip_add() prints own failure message on error. */ |
@@ -1081,6 +1078,8 @@ static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip | |||
1081 | if ((base != NULL) && (chip->base == NULL)) | 1078 | if ((base != NULL) && (chip->base == NULL)) |
1082 | chip->base = base + ((i) * 0x20); | 1079 | chip->base = base + ((i) * 0x20); |
1083 | 1080 | ||
1081 | chip->bitmap_gpio_int = 0; | ||
1082 | |||
1084 | samsung_gpiolib_add(chip); | 1083 | samsung_gpiolib_add(chip); |
1085 | } | 1084 | } |
1086 | } | 1085 | } |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 4800d4c2a7b..32f238f3cae 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1208,6 +1208,14 @@ config SENSORS_TWL4030_MADC | |||
1208 | This driver can also be built as a module. If so it will be called | 1208 | This driver can also be built as a module. If so it will be called |
1209 | twl4030-madc-hwmon. | 1209 | twl4030-madc-hwmon. |
1210 | 1210 | ||
1211 | config SENSORS_VEXPRESS | ||
1212 | tristate "Versatile Express" | ||
1213 | depends on VEXPRESS_CONFIG | ||
1214 | help | ||
1215 | This driver provides support for hardware sensors available on | ||
1216 | the ARM Ltd's Versatile Express platform. It can provide wide | ||
1217 | range of information like temperature, power, energy. | ||
1218 | |||
1211 | config SENSORS_VIA_CPUTEMP | 1219 | config SENSORS_VIA_CPUTEMP |
1212 | tristate "VIA CPU temperature sensor" | 1220 | tristate "VIA CPU temperature sensor" |
1213 | depends on X86 | 1221 | depends on X86 |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index a930f0997d2..5da287443f6 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -122,6 +122,7 @@ obj-$(CONFIG_SENSORS_TMP102) += tmp102.o | |||
122 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o | 122 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o |
123 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o | 123 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o |
124 | obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o | 124 | obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o |
125 | obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o | ||
125 | obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o | 126 | obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o |
126 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o | 127 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o |
127 | obj-$(CONFIG_SENSORS_VT1211) += vt1211.o | 128 | 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 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * Copyright (C) 2012 ARM Limited | ||
12 | */ | ||
13 | |||
14 | #define DRVNAME "vexpress-hwmon" | ||
15 | #define pr_fmt(fmt) DRVNAME ": " fmt | ||
16 | |||
17 | #include <linux/device.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/hwmon.h> | ||
20 | #include <linux/hwmon-sysfs.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of_device.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/vexpress.h> | ||
25 | |||
26 | struct vexpress_hwmon_data { | ||
27 | struct device *hwmon_dev; | ||
28 | struct vexpress_config_func *func; | ||
29 | }; | ||
30 | |||
31 | static ssize_t vexpress_hwmon_name_show(struct device *dev, | ||
32 | struct device_attribute *dev_attr, char *buffer) | ||
33 | { | ||
34 | const char *compatible = of_get_property(dev->of_node, "compatible", | ||
35 | NULL); | ||
36 | |||
37 | return sprintf(buffer, "%s\n", compatible); | ||
38 | } | ||
39 | |||
40 | static ssize_t vexpress_hwmon_label_show(struct device *dev, | ||
41 | struct device_attribute *dev_attr, char *buffer) | ||
42 | { | ||
43 | const char *label = of_get_property(dev->of_node, "label", NULL); | ||
44 | |||
45 | if (!label) | ||
46 | return -ENOENT; | ||
47 | |||
48 | return snprintf(buffer, PAGE_SIZE, "%s\n", label); | ||
49 | } | ||
50 | |||
51 | static ssize_t vexpress_hwmon_u32_show(struct device *dev, | ||
52 | struct device_attribute *dev_attr, char *buffer) | ||
53 | { | ||
54 | struct vexpress_hwmon_data *data = dev_get_drvdata(dev); | ||
55 | int err; | ||
56 | u32 value; | ||
57 | |||
58 | err = vexpress_config_read(data->func, 0, &value); | ||
59 | if (err) | ||
60 | return err; | ||
61 | |||
62 | return snprintf(buffer, PAGE_SIZE, "%u\n", value / | ||
63 | to_sensor_dev_attr(dev_attr)->index); | ||
64 | } | ||
65 | |||
66 | static ssize_t vexpress_hwmon_u64_show(struct device *dev, | ||
67 | struct device_attribute *dev_attr, char *buffer) | ||
68 | { | ||
69 | struct vexpress_hwmon_data *data = dev_get_drvdata(dev); | ||
70 | int err; | ||
71 | u32 value_hi, value_lo; | ||
72 | |||
73 | err = vexpress_config_read(data->func, 0, &value_lo); | ||
74 | if (err) | ||
75 | return err; | ||
76 | |||
77 | err = vexpress_config_read(data->func, 1, &value_hi); | ||
78 | if (err) | ||
79 | return err; | ||
80 | |||
81 | return snprintf(buffer, PAGE_SIZE, "%llu\n", | ||
82 | div_u64(((u64)value_hi << 32) | value_lo, | ||
83 | to_sensor_dev_attr(dev_attr)->index)); | ||
84 | } | ||
85 | |||
86 | static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL); | ||
87 | |||
88 | #define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr) \ | ||
89 | struct attribute *vexpress_hwmon_attrs_##_name[] = { \ | ||
90 | &dev_attr_name.attr, \ | ||
91 | &dev_attr_##_label_attr.attr, \ | ||
92 | &sensor_dev_attr_##_input_attr.dev_attr.attr, \ | ||
93 | NULL \ | ||
94 | } | ||
95 | |||
96 | #if !defined(CONFIG_REGULATOR_VEXPRESS) | ||
97 | static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); | ||
98 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show, | ||
99 | NULL, 1000); | ||
100 | static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input); | ||
101 | static struct attribute_group vexpress_hwmon_group_volt = { | ||
102 | .attrs = vexpress_hwmon_attrs_volt, | ||
103 | }; | ||
104 | #endif | ||
105 | |||
106 | static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); | ||
107 | static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show, | ||
108 | NULL, 1000); | ||
109 | static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input); | ||
110 | static struct attribute_group vexpress_hwmon_group_amp = { | ||
111 | .attrs = vexpress_hwmon_attrs_amp, | ||
112 | }; | ||
113 | |||
114 | static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); | ||
115 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show, | ||
116 | NULL, 1000); | ||
117 | static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input); | ||
118 | static struct attribute_group vexpress_hwmon_group_temp = { | ||
119 | .attrs = vexpress_hwmon_attrs_temp, | ||
120 | }; | ||
121 | |||
122 | static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); | ||
123 | static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show, | ||
124 | NULL, 1); | ||
125 | static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input); | ||
126 | static struct attribute_group vexpress_hwmon_group_power = { | ||
127 | .attrs = vexpress_hwmon_attrs_power, | ||
128 | }; | ||
129 | |||
130 | static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); | ||
131 | static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show, | ||
132 | NULL, 1); | ||
133 | static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input); | ||
134 | static struct attribute_group vexpress_hwmon_group_energy = { | ||
135 | .attrs = vexpress_hwmon_attrs_energy, | ||
136 | }; | ||
137 | |||
138 | static struct of_device_id vexpress_hwmon_of_match[] = { | ||
139 | #if !defined(CONFIG_REGULATOR_VEXPRESS) | ||
140 | { | ||
141 | .compatible = "arm,vexpress-volt", | ||
142 | .data = &vexpress_hwmon_group_volt, | ||
143 | }, | ||
144 | #endif | ||
145 | { | ||
146 | .compatible = "arm,vexpress-amp", | ||
147 | .data = &vexpress_hwmon_group_amp, | ||
148 | }, { | ||
149 | .compatible = "arm,vexpress-temp", | ||
150 | .data = &vexpress_hwmon_group_temp, | ||
151 | }, { | ||
152 | .compatible = "arm,vexpress-power", | ||
153 | .data = &vexpress_hwmon_group_power, | ||
154 | }, { | ||
155 | .compatible = "arm,vexpress-energy", | ||
156 | .data = &vexpress_hwmon_group_energy, | ||
157 | }, | ||
158 | {} | ||
159 | }; | ||
160 | MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match); | ||
161 | |||
162 | static int vexpress_hwmon_probe(struct platform_device *pdev) | ||
163 | { | ||
164 | int err; | ||
165 | const struct of_device_id *match; | ||
166 | struct vexpress_hwmon_data *data; | ||
167 | |||
168 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
169 | if (!data) | ||
170 | return -ENOMEM; | ||
171 | platform_set_drvdata(pdev, data); | ||
172 | |||
173 | match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); | ||
174 | if (!match) | ||
175 | return -ENODEV; | ||
176 | |||
177 | data->func = vexpress_config_func_get_by_dev(&pdev->dev); | ||
178 | if (!data->func) | ||
179 | return -ENODEV; | ||
180 | |||
181 | err = sysfs_create_group(&pdev->dev.kobj, match->data); | ||
182 | if (err) | ||
183 | goto error; | ||
184 | |||
185 | data->hwmon_dev = hwmon_device_register(&pdev->dev); | ||
186 | if (IS_ERR(data->hwmon_dev)) { | ||
187 | err = PTR_ERR(data->hwmon_dev); | ||
188 | goto error; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | |||
193 | error: | ||
194 | sysfs_remove_group(&pdev->dev.kobj, match->data); | ||
195 | vexpress_config_func_put(data->func); | ||
196 | return err; | ||
197 | } | ||
198 | |||
199 | static int __devexit vexpress_hwmon_remove(struct platform_device *pdev) | ||
200 | { | ||
201 | struct vexpress_hwmon_data *data = platform_get_drvdata(pdev); | ||
202 | const struct of_device_id *match; | ||
203 | |||
204 | hwmon_device_unregister(data->hwmon_dev); | ||
205 | |||
206 | match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); | ||
207 | sysfs_remove_group(&pdev->dev.kobj, match->data); | ||
208 | |||
209 | vexpress_config_func_put(data->func); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static struct platform_driver vexpress_hwmon_driver = { | ||
215 | .probe = vexpress_hwmon_probe, | ||
216 | .remove = __devexit_p(vexpress_hwmon_remove), | ||
217 | .driver = { | ||
218 | .name = DRVNAME, | ||
219 | .owner = THIS_MODULE, | ||
220 | .of_match_table = vexpress_hwmon_of_match, | ||
221 | }, | ||
222 | }; | ||
223 | |||
224 | module_platform_driver(vexpress_hwmon_driver); | ||
225 | |||
226 | MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); | ||
227 | MODULE_DESCRIPTION("Versatile Express hwmon sensors driver"); | ||
228 | MODULE_LICENSE("GPL"); | ||
229 | MODULE_ALIAS("platform:vexpress-hwmon"); | ||