Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Lantiq cpu temperature sensor driver
0003  *
0004  * Copyright (C) 2017 Florian Eckert <fe@dev.tdt.de>
0005  */
0006 
0007 #include <linux/bitops.h>
0008 #include <linux/delay.h>
0009 #include <linux/hwmon.h>
0010 #include <linux/hwmon-sysfs.h>
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/of_device.h>
0014 
0015 #include <lantiq_soc.h>
0016 
0017 /* gphy1 configuration register contains cpu temperature */
0018 #define CGU_GPHY1_CR   0x0040
0019 #define CGU_TEMP_PD    BIT(19)
0020 
0021 static void ltq_cputemp_enable(void)
0022 {
0023     ltq_cgu_w32(ltq_cgu_r32(CGU_GPHY1_CR) | CGU_TEMP_PD, CGU_GPHY1_CR);
0024 }
0025 
0026 static void ltq_cputemp_disable(void *data)
0027 {
0028     ltq_cgu_w32(ltq_cgu_r32(CGU_GPHY1_CR) & ~CGU_TEMP_PD, CGU_GPHY1_CR);
0029 }
0030 
0031 static int ltq_read(struct device *dev, enum hwmon_sensor_types type,
0032             u32 attr, int channel, long *temp)
0033 {
0034     int value;
0035 
0036     switch (attr) {
0037     case hwmon_temp_input:
0038         /* get the temperature including one decimal place */
0039         value = (ltq_cgu_r32(CGU_GPHY1_CR) >> 9) & 0x01FF;
0040         value = value * 5;
0041         /* range -38 to +154 °C, register value zero is -38.0 °C */
0042         value -= 380;
0043         /* scale temp to millidegree */
0044         value = value * 100;
0045         break;
0046     default:
0047         return -EOPNOTSUPP;
0048     }
0049 
0050     *temp = value;
0051     return 0;
0052 }
0053 
0054 static umode_t ltq_is_visible(const void *_data, enum hwmon_sensor_types type,
0055                   u32 attr, int channel)
0056 {
0057     if (type != hwmon_temp)
0058         return 0;
0059 
0060     switch (attr) {
0061     case hwmon_temp_input:
0062         return 0444;
0063     default:
0064         return 0;
0065     }
0066 }
0067 
0068 static const struct hwmon_channel_info *ltq_info[] = {
0069     HWMON_CHANNEL_INFO(chip,
0070                HWMON_C_REGISTER_TZ),
0071     HWMON_CHANNEL_INFO(temp,
0072                HWMON_T_INPUT),
0073     NULL
0074 };
0075 
0076 static const struct hwmon_ops ltq_hwmon_ops = {
0077     .is_visible = ltq_is_visible,
0078     .read = ltq_read,
0079 };
0080 
0081 static const struct hwmon_chip_info ltq_chip_info = {
0082     .ops = &ltq_hwmon_ops,
0083     .info = ltq_info,
0084 };
0085 
0086 static int ltq_cputemp_probe(struct platform_device *pdev)
0087 {
0088     struct device *hwmon_dev;
0089     int err = 0;
0090 
0091     /* available on vr9 v1.2 SoCs only */
0092     if (ltq_soc_type() != SOC_TYPE_VR9_2)
0093         return -ENODEV;
0094 
0095     err = devm_add_action(&pdev->dev, ltq_cputemp_disable, NULL);
0096     if (err)
0097         return err;
0098 
0099     ltq_cputemp_enable();
0100 
0101     hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
0102                              "ltq_cputemp",
0103                              NULL,
0104                              &ltq_chip_info,
0105                              NULL);
0106 
0107     if (IS_ERR(hwmon_dev)) {
0108         dev_err(&pdev->dev, "Failed to register as hwmon device");
0109         return PTR_ERR(hwmon_dev);
0110     }
0111 
0112     return 0;
0113 }
0114 
0115 const struct of_device_id ltq_cputemp_match[] = {
0116     { .compatible = "lantiq,cputemp" },
0117     {},
0118 };
0119 MODULE_DEVICE_TABLE(of, ltq_cputemp_match);
0120 
0121 static struct platform_driver ltq_cputemp_driver = {
0122     .probe = ltq_cputemp_probe,
0123     .driver = {
0124         .name = "ltq-cputemp",
0125         .of_match_table = ltq_cputemp_match,
0126     },
0127 };
0128 
0129 module_platform_driver(ltq_cputemp_driver);
0130 
0131 MODULE_AUTHOR("Florian Eckert <fe@dev.tdt.de>");
0132 MODULE_DESCRIPTION("Lantiq cpu temperature sensor driver");
0133 MODULE_LICENSE("GPL");