Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
0004  *
0005  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/types.h>
0010 #include <linux/slab.h>
0011 #include <linux/module.h>
0012 #include <linux/of_device.h>
0013 #include <linux/io.h>
0014 #include <linux/hwmon.h>
0015 #include <linux/hwmon-sysfs.h>
0016 #include <linux/err.h>
0017 
0018 #define DRV_MODULE_VERSION  "0.1"
0019 
0020 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
0021 MODULE_DESCRIPTION("Ultra45 environmental monitor driver");
0022 MODULE_LICENSE("GPL");
0023 MODULE_VERSION(DRV_MODULE_VERSION);
0024 
0025 /* PIC device registers */
0026 #define REG_CMD     0x00UL
0027 #define  REG_CMD_RESET  0x80
0028 #define  REG_CMD_ESTAR  0x01
0029 #define REG_STAT    0x01UL
0030 #define  REG_STAT_FWVER 0xf0
0031 #define  REG_STAT_TGOOD 0x08
0032 #define  REG_STAT_STALE 0x04
0033 #define  REG_STAT_BUSY  0x02
0034 #define  REG_STAT_FAULT 0x01
0035 #define REG_DATA    0x40UL
0036 #define REG_ADDR    0x41UL
0037 #define REG_SIZE    0x42UL
0038 
0039 /* Registers accessed indirectly via REG_DATA/REG_ADDR */
0040 #define IREG_FAN0       0x00
0041 #define IREG_FAN1       0x01
0042 #define IREG_FAN2       0x02
0043 #define IREG_FAN3       0x03
0044 #define IREG_FAN4       0x04
0045 #define IREG_FAN5       0x05
0046 #define IREG_LCL_TEMP       0x06
0047 #define IREG_RMT1_TEMP      0x07
0048 #define IREG_RMT2_TEMP      0x08
0049 #define IREG_RMT3_TEMP      0x09
0050 #define IREG_LM95221_TEMP   0x0a
0051 #define IREG_FIRE_TEMP      0x0b
0052 #define IREG_LSI1064_TEMP   0x0c
0053 #define IREG_FRONT_TEMP     0x0d
0054 #define IREG_FAN_STAT       0x0e
0055 #define IREG_VCORE0     0x0f
0056 #define IREG_VCORE1     0x10
0057 #define IREG_VMEM0      0x11
0058 #define IREG_VMEM1      0x12
0059 #define IREG_PSU_TEMP       0x13
0060 
0061 struct env {
0062     void __iomem    *regs;
0063     spinlock_t  lock;
0064 
0065     struct device   *hwmon_dev;
0066 };
0067 
0068 static u8 env_read(struct env *p, u8 ireg)
0069 {
0070     u8 ret;
0071 
0072     spin_lock(&p->lock);
0073     writeb(ireg, p->regs + REG_ADDR);
0074     ret = readb(p->regs + REG_DATA);
0075     spin_unlock(&p->lock);
0076 
0077     return ret;
0078 }
0079 
0080 static void env_write(struct env *p, u8 ireg, u8 val)
0081 {
0082     spin_lock(&p->lock);
0083     writeb(ireg, p->regs + REG_ADDR);
0084     writeb(val, p->regs + REG_DATA);
0085     spin_unlock(&p->lock);
0086 }
0087 
0088 /*
0089  * There seems to be a adr7462 providing these values, thus a lot
0090  * of these calculations are borrowed from the adt7470 driver.
0091  */
0092 #define FAN_PERIOD_TO_RPM(x)    ((90000 * 60) / (x))
0093 #define FAN_RPM_TO_PERIOD   FAN_PERIOD_TO_RPM
0094 #define FAN_PERIOD_INVALID  (0xff << 8)
0095 #define FAN_DATA_VALID(x)   ((x) && (x) != FAN_PERIOD_INVALID)
0096 
0097 static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr,
0098                   char *buf)
0099 {
0100     int fan_nr = to_sensor_dev_attr(attr)->index;
0101     struct env *p = dev_get_drvdata(dev);
0102     int rpm, period;
0103     u8 val;
0104 
0105     val = env_read(p, IREG_FAN0 + fan_nr);
0106     period = (int) val << 8;
0107     if (FAN_DATA_VALID(period))
0108         rpm = FAN_PERIOD_TO_RPM(period);
0109     else
0110         rpm = 0;
0111 
0112     return sprintf(buf, "%d\n", rpm);
0113 }
0114 
0115 static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
0116                  const char *buf, size_t count)
0117 {
0118     int fan_nr = to_sensor_dev_attr(attr)->index;
0119     unsigned long rpm;
0120     struct env *p = dev_get_drvdata(dev);
0121     int period;
0122     u8 val;
0123     int err;
0124 
0125     err = kstrtoul(buf, 10, &rpm);
0126     if (err)
0127         return err;
0128 
0129     if (!rpm)
0130         return -EINVAL;
0131 
0132     period = FAN_RPM_TO_PERIOD(rpm);
0133     val = period >> 8;
0134     env_write(p, IREG_FAN0 + fan_nr, val);
0135 
0136     return count;
0137 }
0138 
0139 static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr,
0140                   char *buf)
0141 {
0142     int fan_nr = to_sensor_dev_attr(attr)->index;
0143     struct env *p = dev_get_drvdata(dev);
0144     u8 val = env_read(p, IREG_FAN_STAT);
0145     return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
0146 }
0147 
0148 #define fan(index)                          \
0149 static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR,    \
0150         show_fan_speed, set_fan_speed, index);          \
0151 static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO,          \
0152         show_fan_fault, NULL, index)
0153 
0154 fan(0);
0155 fan(1);
0156 fan(2);
0157 fan(3);
0158 fan(4);
0159 
0160 static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6);
0161 
0162 static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
0163              char *buf)
0164 {
0165     int temp_nr = to_sensor_dev_attr(attr)->index;
0166     struct env *p = dev_get_drvdata(dev);
0167     s8 val;
0168 
0169     val = env_read(p, IREG_LCL_TEMP + temp_nr);
0170     return sprintf(buf, "%d\n", ((int) val) - 64);
0171 }
0172 
0173 static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0);
0174 static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1);
0175 static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2);
0176 static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3);
0177 static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4);
0178 static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5);
0179 static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6);
0180 static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7);
0181 static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13);
0182 
0183 static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr,
0184                  char *buf)
0185 {
0186     int index = to_sensor_dev_attr(attr)->index;
0187     struct env *p = dev_get_drvdata(dev);
0188     u8 val;
0189 
0190     val = readb(p->regs + REG_STAT);
0191     return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0);
0192 }
0193 
0194 static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0);
0195 static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1);
0196 static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2);
0197 static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL,
0198               3);
0199 
0200 static ssize_t show_fwver(struct device *dev, struct device_attribute *attr,
0201               char *buf)
0202 {
0203     struct env *p = dev_get_drvdata(dev);
0204     u8 val;
0205 
0206     val = readb(p->regs + REG_STAT);
0207     return sprintf(buf, "%d\n", val >> 4);
0208 }
0209 
0210 static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0);
0211 
0212 static ssize_t show_name(struct device *dev, struct device_attribute *attr,
0213              char *buf)
0214 {
0215     return sprintf(buf, "ultra45\n");
0216 }
0217 
0218 static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
0219 
0220 static struct attribute *env_attributes[] = {
0221     &sensor_dev_attr_fan0_speed.dev_attr.attr,
0222     &sensor_dev_attr_fan0_fault.dev_attr.attr,
0223     &sensor_dev_attr_fan1_speed.dev_attr.attr,
0224     &sensor_dev_attr_fan1_fault.dev_attr.attr,
0225     &sensor_dev_attr_fan2_speed.dev_attr.attr,
0226     &sensor_dev_attr_fan2_fault.dev_attr.attr,
0227     &sensor_dev_attr_fan3_speed.dev_attr.attr,
0228     &sensor_dev_attr_fan3_fault.dev_attr.attr,
0229     &sensor_dev_attr_fan4_speed.dev_attr.attr,
0230     &sensor_dev_attr_fan4_fault.dev_attr.attr,
0231     &sensor_dev_attr_psu_fan_fault.dev_attr.attr,
0232     &sensor_dev_attr_adt7462_local_temp.dev_attr.attr,
0233     &sensor_dev_attr_cpu0_temp.dev_attr.attr,
0234     &sensor_dev_attr_cpu1_temp.dev_attr.attr,
0235     &sensor_dev_attr_motherboard_temp.dev_attr.attr,
0236     &sensor_dev_attr_lm95221_local_temp.dev_attr.attr,
0237     &sensor_dev_attr_fire_temp.dev_attr.attr,
0238     &sensor_dev_attr_lsi1064_local_temp.dev_attr.attr,
0239     &sensor_dev_attr_front_panel_temp.dev_attr.attr,
0240     &sensor_dev_attr_psu_temp.dev_attr.attr,
0241     &sensor_dev_attr_fan_failure.dev_attr.attr,
0242     &sensor_dev_attr_env_bus_busy.dev_attr.attr,
0243     &sensor_dev_attr_env_data_stale.dev_attr.attr,
0244     &sensor_dev_attr_tpm_self_test_passed.dev_attr.attr,
0245     &sensor_dev_attr_firmware_version.dev_attr.attr,
0246     &sensor_dev_attr_name.dev_attr.attr,
0247     NULL,
0248 };
0249 
0250 static const struct attribute_group env_group = {
0251     .attrs = env_attributes,
0252 };
0253 
0254 static int env_probe(struct platform_device *op)
0255 {
0256     struct env *p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
0257     int err = -ENOMEM;
0258 
0259     if (!p)
0260         goto out;
0261 
0262     spin_lock_init(&p->lock);
0263 
0264     p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
0265     if (!p->regs)
0266         goto out;
0267 
0268     err = sysfs_create_group(&op->dev.kobj, &env_group);
0269     if (err)
0270         goto out_iounmap;
0271 
0272     p->hwmon_dev = hwmon_device_register(&op->dev);
0273     if (IS_ERR(p->hwmon_dev)) {
0274         err = PTR_ERR(p->hwmon_dev);
0275         goto out_sysfs_remove_group;
0276     }
0277 
0278     platform_set_drvdata(op, p);
0279     err = 0;
0280 
0281 out:
0282     return err;
0283 
0284 out_sysfs_remove_group:
0285     sysfs_remove_group(&op->dev.kobj, &env_group);
0286 
0287 out_iounmap:
0288     of_iounmap(&op->resource[0], p->regs, REG_SIZE);
0289 
0290     goto out;
0291 }
0292 
0293 static int env_remove(struct platform_device *op)
0294 {
0295     struct env *p = platform_get_drvdata(op);
0296 
0297     if (p) {
0298         sysfs_remove_group(&op->dev.kobj, &env_group);
0299         hwmon_device_unregister(p->hwmon_dev);
0300         of_iounmap(&op->resource[0], p->regs, REG_SIZE);
0301     }
0302 
0303     return 0;
0304 }
0305 
0306 static const struct of_device_id env_match[] = {
0307     {
0308         .name = "env-monitor",
0309         .compatible = "SUNW,ebus-pic16f747-env",
0310     },
0311     {},
0312 };
0313 MODULE_DEVICE_TABLE(of, env_match);
0314 
0315 static struct platform_driver env_driver = {
0316     .driver = {
0317         .name = "ultra45_env",
0318         .of_match_table = env_match,
0319     },
0320     .probe      = env_probe,
0321     .remove     = env_remove,
0322 };
0323 
0324 module_platform_driver(env_driver);