0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/fs.h>
0011 #include <linux/errno.h>
0012 #include <linux/init.h>
0013 #include <linux/miscdevice.h>
0014 #include <linux/pm.h>
0015 #include <linux/of.h>
0016 #include <linux/of_device.h>
0017 #include <linux/module.h>
0018
0019 #include <asm/io.h>
0020 #include <asm/oplib.h>
0021 #include <linux/uaccess.h>
0022 #include <asm/auxio.h>
0023 #include <asm/apc.h>
0024 #include <asm/processor.h>
0025
0026
0027
0028
0029
0030
0031 #define APC_MINOR MISC_DYNAMIC_MINOR
0032 #define APC_OBPNAME "power-management"
0033 #define APC_DEVNAME "apc"
0034
0035 static u8 __iomem *regs;
0036 static int apc_no_idle = 0;
0037
0038 #define apc_readb(offs) (sbus_readb(regs+offs))
0039 #define apc_writeb(val, offs) (sbus_writeb(val, regs+offs))
0040
0041
0042
0043
0044
0045
0046
0047 static int __init apc_setup(char *str)
0048 {
0049 if(!strncmp(str, "noidle", strlen("noidle"))) {
0050 apc_no_idle = 1;
0051 return 1;
0052 }
0053 return 0;
0054 }
0055 __setup("apc=", apc_setup);
0056
0057
0058
0059
0060
0061 static void apc_swift_idle(void)
0062 {
0063 #ifdef APC_DEBUG_LED
0064 set_auxio(0x00, AUXIO_LED);
0065 #endif
0066
0067 apc_writeb(apc_readb(APC_IDLE_REG) | APC_IDLE_ON, APC_IDLE_REG);
0068
0069 #ifdef APC_DEBUG_LED
0070 set_auxio(AUXIO_LED, 0x00);
0071 #endif
0072 }
0073
0074 static inline void apc_free(struct platform_device *op)
0075 {
0076 of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
0077 }
0078
0079 static int apc_open(struct inode *inode, struct file *f)
0080 {
0081 return 0;
0082 }
0083
0084 static int apc_release(struct inode *inode, struct file *f)
0085 {
0086 return 0;
0087 }
0088
0089 static long apc_ioctl(struct file *f, unsigned int cmd, unsigned long __arg)
0090 {
0091 __u8 inarg, __user *arg = (__u8 __user *) __arg;
0092
0093 switch (cmd) {
0094 case APCIOCGFANCTL:
0095 if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg))
0096 return -EFAULT;
0097 break;
0098
0099 case APCIOCGCPWR:
0100 if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg))
0101 return -EFAULT;
0102 break;
0103
0104 case APCIOCGBPORT:
0105 if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg))
0106 return -EFAULT;
0107 break;
0108
0109 case APCIOCSFANCTL:
0110 if (get_user(inarg, arg))
0111 return -EFAULT;
0112 apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
0113 break;
0114
0115 case APCIOCSCPWR:
0116 if (get_user(inarg, arg))
0117 return -EFAULT;
0118 apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
0119 break;
0120
0121 case APCIOCSBPORT:
0122 if (get_user(inarg, arg))
0123 return -EFAULT;
0124 apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
0125 break;
0126
0127 default:
0128 return -EINVAL;
0129 }
0130
0131 return 0;
0132 }
0133
0134 static const struct file_operations apc_fops = {
0135 .unlocked_ioctl = apc_ioctl,
0136 .open = apc_open,
0137 .release = apc_release,
0138 .llseek = noop_llseek,
0139 };
0140
0141 static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
0142
0143 static int apc_probe(struct platform_device *op)
0144 {
0145 int err;
0146
0147 regs = of_ioremap(&op->resource[0], 0,
0148 resource_size(&op->resource[0]), APC_OBPNAME);
0149 if (!regs) {
0150 printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
0151 return -ENODEV;
0152 }
0153
0154 err = misc_register(&apc_miscdev);
0155 if (err) {
0156 printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
0157 apc_free(op);
0158 return -ENODEV;
0159 }
0160
0161
0162 if (!apc_no_idle)
0163 sparc_idle = apc_swift_idle;
0164
0165 printk(KERN_INFO "%s: power management initialized%s\n",
0166 APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
0167
0168 return 0;
0169 }
0170
0171 static const struct of_device_id apc_match[] = {
0172 {
0173 .name = APC_OBPNAME,
0174 },
0175 {},
0176 };
0177 MODULE_DEVICE_TABLE(of, apc_match);
0178
0179 static struct platform_driver apc_driver = {
0180 .driver = {
0181 .name = "apc",
0182 .of_match_table = apc_match,
0183 },
0184 .probe = apc_probe,
0185 };
0186
0187 static int __init apc_init(void)
0188 {
0189 return platform_driver_register(&apc_driver);
0190 }
0191
0192
0193
0194
0195
0196 __initcall(apc_init);