diff options
Diffstat (limited to 'drivers/sbus/char/envctrl.c')
| -rw-r--r-- | drivers/sbus/char/envctrl.c | 262 |
1 files changed, 126 insertions, 136 deletions
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index b0cc3c2588f..af15a2fdab5 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1,5 +1,4 @@ -/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $ - * envctrl.c: Temperature and Fan monitoring on Machines providing it. +/* envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com) @@ -19,25 +18,23 @@ * Daniele Bellucci <bellucda@tiscali.it> */ -#define __KERNEL_SYSCALLS__ -static int errno; - -#include <linux/config.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/kthread.h> -#include <linux/errno.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/init.h> #include <linux/miscdevice.h> -#include <linux/mm.h> +#include <linux/kmod.h> +#include <linux/reboot.h> #include <linux/slab.h> -#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_device.h> -#include <asm/ebus.h> #include <asm/uaccess.h> #include <asm/envctrl.h> +#include <asm/io.h> + +#define DRIVER_NAME "envctrl" +#define PFX DRIVER_NAME ": " #define ENVCTRL_MINOR 162 @@ -94,11 +91,11 @@ static int errno; #define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */ #define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */ #define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */ -#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */ +#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperature */ /* monitor */ #define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */ #define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */ -#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */ +#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperature */ #define ENVCTRL_GLOBALADDR_MON 8 /* global address */ /* Child device type. @@ -198,7 +195,7 @@ static void envtrl_i2c_test_pin(void) } if (limit <= 0) - printk(KERN_INFO "envctrl: Pin status will not clear.\n"); + printk(KERN_INFO PFX "Pin status will not clear.\n"); } /* Function Description: Test busy bit. @@ -216,7 +213,7 @@ static void envctrl_i2c_test_bb(void) } if (limit <= 0) - printk(KERN_INFO "envctrl: Busy bit will not clear.\n"); + printk(KERN_INFO PFX "Busy bit will not clear.\n"); } /* Function Description: Send the address for a read access. @@ -355,7 +352,7 @@ static int envctrl_i2c_data_translate(unsigned char data, int translate_type, default: break; - }; + } return len; } @@ -646,7 +643,7 @@ envctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) default: break; - }; + } return ret; } @@ -654,9 +651,8 @@ envctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) /* Function Description: Command what to read. Mapped to user ioctl(). * Return: Gives 0 for implemented commands, -EINVAL otherwise. */ -static int -envctrl_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long +envctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { char __user *infobuf; @@ -690,7 +686,7 @@ envctrl_ioctl(struct inode *inode, struct file *file, default: return -EINVAL; - }; + } return 0; } @@ -714,12 +710,16 @@ envctrl_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations envctrl_fops = { - .owner = THIS_MODULE, - .read = envctrl_read, - .ioctl = envctrl_ioctl, - .open = envctrl_open, - .release = envctrl_release, +static const struct file_operations envctrl_fops = { + .owner = THIS_MODULE, + .read = envctrl_read, + .unlocked_ioctl = envctrl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = envctrl_ioctl, +#endif + .open = envctrl_open, + .release = envctrl_release, + .llseek = noop_llseek, }; static struct miscdevice envctrl_dev = { @@ -732,7 +732,7 @@ static struct miscdevice envctrl_dev = { * Return: None. */ static void envctrl_set_mon(struct i2c_child_t *pchild, - char *chnl_desc, + const char *chnl_desc, int chnl_no) { /* Firmware only has temperature type. It does not distinguish @@ -766,16 +766,14 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, * decoding tables, monitor type, optional properties. * Return: None. */ -static void envctrl_init_adc(struct i2c_child_t *pchild, int node) +static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp) { - char chnls_desc[CHANNEL_DESC_SZ]; int i = 0, len; - char *pos = chnls_desc; + const char *pos; + const unsigned int *pval; /* Firmware describe channels into a stream separated by a '\0'. */ - len = prom_getproperty(node, "channels-description", chnls_desc, - CHANNEL_DESC_SZ); - chnls_desc[CHANNEL_DESC_SZ - 1] = '\0'; + pos = of_get_property(dp, "channels-description", &len); while (len > 0) { int l = strlen(pos) + 1; @@ -785,10 +783,13 @@ static void envctrl_init_adc(struct i2c_child_t *pchild, int node) } /* Get optional properties. */ - len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature, - sizeof(warning_temperature)); - len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature, - sizeof(shutdown_temperature)); + pval = of_get_property(dp, "warning-temp", NULL); + if (pval) + warning_temperature = *pval; + + pval = of_get_property(dp, "shutdown-temp", NULL); + if (pval) + shutdown_temperature = *pval; } /* Function Description: Initialize child device monitoring fan status. @@ -859,24 +860,20 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) /* Function Description: Initialize i2c child device. * Return: None. */ -static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, +static void envctrl_init_i2c_child(struct device_node *dp, struct i2c_child_t *pchild) { - int node, len, i, tbls_size = 0; - - node = edev_child->prom_node; + int len, i, tbls_size = 0; + const void *pval; /* Get device address. */ - len = prom_getproperty(node, "reg", - (char *) &(pchild->addr), - sizeof(pchild->addr)); + pval = of_get_property(dp, "reg", &len); + memcpy(&pchild->addr, pval, len); /* Get tables property. Read firmware temperature tables. */ - len = prom_getproperty(node, "translation", - (char *) pchild->tblprop_array, - (PCF8584_MAX_CHANNELS * - sizeof(struct pcf8584_tblprop))); - if (len > 0) { + pval = of_get_property(dp, "translation", &len); + if (pval && len > 0) { + memcpy(pchild->tblprop_array, pval, len); pchild->total_tbls = len / sizeof(struct pcf8584_tblprop); for (i = 0; i < pchild->total_tbls; i++) { if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) { @@ -886,15 +883,15 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, pchild->tables = kmalloc(tbls_size, GFP_KERNEL); if (pchild->tables == NULL){ - printk("envctrl: Failed to allocate table.\n"); + printk(KERN_ERR PFX "Failed to allocate table.\n"); return; } - len = prom_getproperty(node, "tables", - (char *) pchild->tables, tbls_size); - if (len <= 0) { - printk("envctrl: Failed to get table.\n"); + pval = of_get_property(dp, "tables", &len); + if (!pval || len <= 0) { + printk(KERN_ERR PFX "Failed to get table.\n"); return; } + memcpy(pchild->tables, pval, len); } /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04) @@ -905,12 +902,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, * 'NULL' monitor type. */ if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) { + struct device_node *root_node; int len; - char prop[56]; - len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); - if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) - { + root_node = of_find_node_by_path("/"); + if (!strcmp(root_node->name, "SUNW,UltraSPARC-IIi-cEngine")) { for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) { pchild->mon_type[len] = ENVCTRL_NOMON; } @@ -919,16 +915,14 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, } /* Get the monitor channels. */ - len = prom_getproperty(node, "channels-in-use", - (char *) pchild->chnl_array, - (PCF8584_MAX_CHANNELS * - sizeof(struct pcf8584_channel))); + pval = of_get_property(dp, "channels-in-use", &len); + memcpy(pchild->chnl_array, pval, len); pchild->total_chnls = len / sizeof(struct pcf8584_channel); for (i = 0; i < pchild->total_chnls; i++) { switch (pchild->chnl_array[i].type) { case PCF8584_TEMP_TYPE: - envctrl_init_adc(pchild, node); + envctrl_init_adc(pchild, dp); break; case PCF8584_GLOBALADDR_TYPE: @@ -943,7 +937,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, case PCF8584_VOLTAGE_TYPE: if (pchild->i2ctype == I2C_ADC) { - envctrl_init_adc(pchild,node); + envctrl_init_adc(pchild,dp); } else { envctrl_init_voltage_status(pchild); } @@ -952,7 +946,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, default: break; - }; + } } } @@ -976,17 +970,15 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type) static void envctrl_do_shutdown(void) { static int inprog = 0; - static char *envp[] = { - "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - char *argv[] = { - "/sbin/shutdown", "-h", "now", NULL }; + int ret; if (inprog != 0) return; inprog = 1; printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n"); - if (0 > execve("/sbin/shutdown", argv, envp)) { + ret = orderly_poweroff(true); + if (ret < 0) { printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); inprog = 0; /* unlikely to succeed, but we could try again */ } @@ -1002,14 +994,14 @@ static int kenvctrld(void *__unused) struct i2c_child_t *cputemp; if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) { - printk(KERN_ERR - "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n"); + printk(KERN_ERR PFX + "kenvctrld unable to monitor CPU temp-- exiting\n"); return -ENODEV; } poll_interval = 5000; /* TODO env_mon_interval */ - printk(KERN_INFO "envctrl: %s starting...\n", current->comm); + printk(KERN_INFO PFX "%s starting...\n", current->comm); for (;;) { msleep_interruptible(poll_interval); @@ -1031,54 +1023,34 @@ static int kenvctrld(void *__unused) } } } - printk(KERN_INFO "envctrl: %s exiting...\n", current->comm); + printk(KERN_INFO PFX "%s exiting...\n", current->comm); return 0; } -static int __init envctrl_init(void) +static int envctrl_probe(struct platform_device *op) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - struct linux_ebus_child *edev_child = NULL; - int err, i = 0; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "bbc")) { - /* If we find a boot-bus controller node, - * then this envctrl driver is not for us. - */ - return -ENODEV; - } - } - } + struct device_node *dp; + int index, err; - /* Traverse through ebus and ebus device list for i2c device and - * adc and gpio nodes. - */ - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "i2c")) { - i2c = ioremap(edev->resource[0].start, 0x2); - for_each_edevchild(edev, edev_child) { - if (!strcmp("gpio", edev_child->prom_name)) { - i2c_childlist[i].i2ctype = I2C_GPIO; - envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); - } - if (!strcmp("adc", edev_child->prom_name)) { - i2c_childlist[i].i2ctype = I2C_ADC; - envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); - } - } - goto done; - } + if (i2c) + return -EINVAL; + + i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME); + if (!i2c) + return -ENOMEM; + + index = 0; + dp = op->dev.of_node->child; + while (dp) { + if (!strcmp(dp->name, "gpio")) { + i2c_childlist[index].i2ctype = I2C_GPIO; + envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); + } else if (!strcmp(dp->name, "adc")) { + i2c_childlist[index].i2ctype = I2C_ADC; + envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); } - } -done: - if (!edev) { - printk("envctrl: I2C device not found.\n"); - return -ENODEV; + dp = dp->sibling; } /* Set device address. */ @@ -1096,7 +1068,7 @@ done: /* Register the device as a minor miscellaneous device. */ err = misc_register(&envctrl_dev); if (err) { - printk("envctrl: Unable to get misc minor %d\n", + printk(KERN_ERR PFX "Unable to get misc minor %d\n", envctrl_dev.minor); goto out_iounmap; } @@ -1105,12 +1077,12 @@ done: * a next child device, so we decrement before reverse-traversal of * child devices. */ - printk("envctrl: initialized "); - for (--i; i >= 0; --i) { + printk(KERN_INFO PFX "Initialized "); + for (--index; index >= 0; --index) { printk("[%s 0x%lx]%s", - (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : - ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), - i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); + (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" : + ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"), + i2c_childlist[index].addr, (0 == index) ? "\n" : " "); } kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); @@ -1124,29 +1096,47 @@ done: out_deregister: misc_deregister(&envctrl_dev); out_iounmap: - iounmap(i2c); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) { - if (i2c_childlist[i].tables) - kfree(i2c_childlist[i].tables); - } + of_iounmap(&op->resource[0], i2c, 0x2); + for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) + kfree(i2c_childlist[index].tables); + return err; } -static void __exit envctrl_cleanup(void) +static int envctrl_remove(struct platform_device *op) { - int i; + int index; kthread_stop(kenvctrld_task); - iounmap(i2c); + of_iounmap(&op->resource[0], i2c, 0x2); misc_deregister(&envctrl_dev); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) { - if (i2c_childlist[i].tables) - kfree(i2c_childlist[i].tables); - } + for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) + kfree(i2c_childlist[index].tables); + + return 0; } -module_init(envctrl_init); -module_exit(envctrl_cleanup); +static const struct of_device_id envctrl_match[] = { + { + .name = "i2c", + .compatible = "i2cpcf,8584", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, envctrl_match); + +static struct platform_driver envctrl_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = envctrl_match, + }, + .probe = envctrl_probe, + .remove = envctrl_remove, +}; + +module_platform_driver(envctrl_driver); + MODULE_LICENSE("GPL"); |
