| .. | .. |
|---|
| 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 | } |
|---|