.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * TI Bandgap temperature sensor driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | * Author: Moiz Sonasath <m-sonasath@ti.com> |
---|
7 | 8 | * Couple of fixes, DT and MFD adaptation: |
---|
8 | 9 | * Eduardo Valentin <eduardo.valentin@ti.com> |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or |
---|
11 | | - * modify it under the terms of the GNU General Public License |
---|
12 | | - * version 2 as published by the Free Software Foundation. |
---|
13 | | - * |
---|
14 | | - * This program is distributed in the hope that it will be useful, but |
---|
15 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
17 | | - * General Public License for more details. |
---|
18 | | - * |
---|
19 | | - * You should have received a copy of the GNU General Public License |
---|
20 | | - * along with this program; if not, write to the Free Software |
---|
21 | | - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
---|
22 | | - * 02110-1301 USA |
---|
23 | | - * |
---|
24 | 10 | */ |
---|
25 | 11 | |
---|
26 | 12 | #include <linux/module.h> |
---|
.. | .. |
---|
29 | 15 | #include <linux/kernel.h> |
---|
30 | 16 | #include <linux/interrupt.h> |
---|
31 | 17 | #include <linux/clk.h> |
---|
32 | | -#include <linux/gpio.h> |
---|
| 18 | +#include <linux/gpio/consumer.h> |
---|
33 | 19 | #include <linux/platform_device.h> |
---|
34 | 20 | #include <linux/err.h> |
---|
35 | 21 | #include <linux/types.h> |
---|
36 | 22 | #include <linux/spinlock.h> |
---|
| 23 | +#include <linux/sys_soc.h> |
---|
37 | 24 | #include <linux/reboot.h> |
---|
38 | 25 | #include <linux/of_device.h> |
---|
39 | 26 | #include <linux/of_platform.h> |
---|
40 | 27 | #include <linux/of_irq.h> |
---|
41 | | -#include <linux/of_gpio.h> |
---|
42 | 28 | #include <linux/io.h> |
---|
| 29 | +#include <linux/cpu_pm.h> |
---|
| 30 | +#include <linux/device.h> |
---|
| 31 | +#include <linux/pm_runtime.h> |
---|
| 32 | +#include <linux/pm.h> |
---|
| 33 | +#include <linux/of.h> |
---|
| 34 | +#include <linux/of_device.h> |
---|
43 | 35 | |
---|
44 | 36 | #include "ti-bandgap.h" |
---|
45 | 37 | |
---|
46 | 38 | static int ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id); |
---|
| 39 | +#ifdef CONFIG_PM_SLEEP |
---|
| 40 | +static int bandgap_omap_cpu_notifier(struct notifier_block *nb, |
---|
| 41 | + unsigned long cmd, void *v); |
---|
| 42 | +#endif |
---|
47 | 43 | |
---|
48 | 44 | /*** Helper functions to access registers and their bitfields ***/ |
---|
49 | 45 | |
---|
.. | .. |
---|
757 | 753 | static int ti_bandgap_tshut_init(struct ti_bandgap *bgp, |
---|
758 | 754 | struct platform_device *pdev) |
---|
759 | 755 | { |
---|
760 | | - int gpio_nr = bgp->tshut_gpio; |
---|
761 | 756 | int status; |
---|
762 | 757 | |
---|
763 | | - /* Request for gpio_86 line */ |
---|
764 | | - status = gpio_request(gpio_nr, "tshut"); |
---|
765 | | - if (status < 0) { |
---|
766 | | - dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86); |
---|
767 | | - return status; |
---|
768 | | - } |
---|
769 | | - status = gpio_direction_input(gpio_nr); |
---|
770 | | - if (status) { |
---|
771 | | - dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr); |
---|
772 | | - return status; |
---|
773 | | - } |
---|
774 | | - |
---|
775 | | - status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler, |
---|
| 758 | + status = request_irq(gpiod_to_irq(bgp->tshut_gpiod), |
---|
| 759 | + ti_bandgap_tshut_irq_handler, |
---|
776 | 760 | IRQF_TRIGGER_RISING, "tshut", NULL); |
---|
777 | | - if (status) { |
---|
778 | | - gpio_free(gpio_nr); |
---|
| 761 | + if (status) |
---|
779 | 762 | dev_err(bgp->dev, "request irq failed for TSHUT"); |
---|
780 | | - } |
---|
781 | 763 | |
---|
782 | 764 | return 0; |
---|
783 | 765 | } |
---|
.. | .. |
---|
801 | 783 | int ret; |
---|
802 | 784 | |
---|
803 | 785 | bgp->irq = platform_get_irq(pdev, 0); |
---|
804 | | - if (bgp->irq < 0) { |
---|
805 | | - dev_err(&pdev->dev, "get_irq failed\n"); |
---|
| 786 | + if (bgp->irq < 0) |
---|
806 | 787 | return bgp->irq; |
---|
807 | | - } |
---|
| 788 | + |
---|
808 | 789 | ret = request_threaded_irq(bgp->irq, NULL, |
---|
809 | 790 | ti_bandgap_talert_irq_handler, |
---|
810 | 791 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, |
---|
.. | .. |
---|
874 | 855 | } while (res); |
---|
875 | 856 | |
---|
876 | 857 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { |
---|
877 | | - bgp->tshut_gpio = of_get_gpio(node, 0); |
---|
878 | | - if (!gpio_is_valid(bgp->tshut_gpio)) { |
---|
879 | | - dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n", |
---|
880 | | - bgp->tshut_gpio); |
---|
881 | | - return ERR_PTR(-EINVAL); |
---|
| 858 | + bgp->tshut_gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN); |
---|
| 859 | + if (IS_ERR(bgp->tshut_gpiod)) { |
---|
| 860 | + dev_err(&pdev->dev, "invalid gpio for tshut\n"); |
---|
| 861 | + return ERR_CAST(bgp->tshut_gpiod); |
---|
882 | 862 | } |
---|
883 | 863 | } |
---|
884 | 864 | |
---|
885 | 865 | return bgp; |
---|
886 | 866 | } |
---|
| 867 | + |
---|
| 868 | +/* |
---|
| 869 | + * List of SoCs on which the CPU PM notifier can cause erros on the DTEMP |
---|
| 870 | + * readout. |
---|
| 871 | + * Enabled notifier on these machines results in erroneous, random values which |
---|
| 872 | + * could trigger unexpected thermal shutdown. |
---|
| 873 | + */ |
---|
| 874 | +static const struct soc_device_attribute soc_no_cpu_notifier[] = { |
---|
| 875 | + { .machine = "OMAP4430" }, |
---|
| 876 | + { /* sentinel */ }, |
---|
| 877 | +}; |
---|
887 | 878 | |
---|
888 | 879 | /*** Device driver call backs ***/ |
---|
889 | 880 | |
---|
.. | .. |
---|
1039 | 1030 | } |
---|
1040 | 1031 | } |
---|
1041 | 1032 | |
---|
| 1033 | +#ifdef CONFIG_PM_SLEEP |
---|
| 1034 | + bgp->nb.notifier_call = bandgap_omap_cpu_notifier; |
---|
| 1035 | + if (!soc_device_match(soc_no_cpu_notifier)) |
---|
| 1036 | + cpu_pm_register_notifier(&bgp->nb); |
---|
| 1037 | +#endif |
---|
| 1038 | + |
---|
1042 | 1039 | return 0; |
---|
1043 | 1040 | |
---|
1044 | 1041 | remove_last_cooling: |
---|
.. | .. |
---|
1060 | 1057 | put_fclock: |
---|
1061 | 1058 | clk_put(bgp->fclock); |
---|
1062 | 1059 | free_irqs: |
---|
1063 | | - if (TI_BANDGAP_HAS(bgp, TSHUT)) { |
---|
1064 | | - free_irq(gpio_to_irq(bgp->tshut_gpio), NULL); |
---|
1065 | | - gpio_free(bgp->tshut_gpio); |
---|
1066 | | - } |
---|
| 1060 | + if (TI_BANDGAP_HAS(bgp, TSHUT)) |
---|
| 1061 | + free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL); |
---|
1067 | 1062 | |
---|
1068 | 1063 | return ret; |
---|
1069 | 1064 | } |
---|
.. | .. |
---|
1074 | 1069 | struct ti_bandgap *bgp = platform_get_drvdata(pdev); |
---|
1075 | 1070 | int i; |
---|
1076 | 1071 | |
---|
1077 | | - /* First thing is to remove sensor interfaces */ |
---|
| 1072 | + if (!soc_device_match(soc_no_cpu_notifier)) |
---|
| 1073 | + cpu_pm_unregister_notifier(&bgp->nb); |
---|
| 1074 | + |
---|
| 1075 | + /* Remove sensor interfaces */ |
---|
1078 | 1076 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
---|
1079 | 1077 | if (bgp->conf->sensors[i].unregister_cooling) |
---|
1080 | 1078 | bgp->conf->sensors[i].unregister_cooling(bgp, i); |
---|
.. | .. |
---|
1093 | 1091 | if (TI_BANDGAP_HAS(bgp, TALERT)) |
---|
1094 | 1092 | free_irq(bgp->irq, bgp); |
---|
1095 | 1093 | |
---|
1096 | | - if (TI_BANDGAP_HAS(bgp, TSHUT)) { |
---|
1097 | | - free_irq(gpio_to_irq(bgp->tshut_gpio), NULL); |
---|
1098 | | - gpio_free(bgp->tshut_gpio); |
---|
1099 | | - } |
---|
| 1094 | + if (TI_BANDGAP_HAS(bgp, TSHUT)) |
---|
| 1095 | + free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL); |
---|
1100 | 1096 | |
---|
1101 | 1097 | return 0; |
---|
1102 | 1098 | } |
---|
.. | .. |
---|
1185 | 1181 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
---|
1186 | 1182 | clk_disable_unprepare(bgp->fclock); |
---|
1187 | 1183 | |
---|
| 1184 | + bgp->is_suspended = true; |
---|
| 1185 | + |
---|
1188 | 1186 | return err; |
---|
| 1187 | +} |
---|
| 1188 | + |
---|
| 1189 | +static int bandgap_omap_cpu_notifier(struct notifier_block *nb, |
---|
| 1190 | + unsigned long cmd, void *v) |
---|
| 1191 | +{ |
---|
| 1192 | + struct ti_bandgap *bgp; |
---|
| 1193 | + |
---|
| 1194 | + bgp = container_of(nb, struct ti_bandgap, nb); |
---|
| 1195 | + |
---|
| 1196 | + spin_lock(&bgp->lock); |
---|
| 1197 | + switch (cmd) { |
---|
| 1198 | + case CPU_CLUSTER_PM_ENTER: |
---|
| 1199 | + if (bgp->is_suspended) |
---|
| 1200 | + break; |
---|
| 1201 | + ti_bandgap_save_ctxt(bgp); |
---|
| 1202 | + ti_bandgap_power(bgp, false); |
---|
| 1203 | + if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
---|
| 1204 | + clk_disable(bgp->fclock); |
---|
| 1205 | + break; |
---|
| 1206 | + case CPU_CLUSTER_PM_ENTER_FAILED: |
---|
| 1207 | + case CPU_CLUSTER_PM_EXIT: |
---|
| 1208 | + if (bgp->is_suspended) |
---|
| 1209 | + break; |
---|
| 1210 | + if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
---|
| 1211 | + clk_enable(bgp->fclock); |
---|
| 1212 | + ti_bandgap_power(bgp, true); |
---|
| 1213 | + ti_bandgap_restore_ctxt(bgp); |
---|
| 1214 | + break; |
---|
| 1215 | + } |
---|
| 1216 | + spin_unlock(&bgp->lock); |
---|
| 1217 | + |
---|
| 1218 | + return NOTIFY_OK; |
---|
1189 | 1219 | } |
---|
1190 | 1220 | |
---|
1191 | 1221 | static int ti_bandgap_resume(struct device *dev) |
---|
.. | .. |
---|
1196 | 1226 | clk_prepare_enable(bgp->fclock); |
---|
1197 | 1227 | |
---|
1198 | 1228 | ti_bandgap_power(bgp, true); |
---|
| 1229 | + bgp->is_suspended = false; |
---|
1199 | 1230 | |
---|
1200 | 1231 | return ti_bandgap_restore_ctxt(bgp); |
---|
1201 | 1232 | } |
---|