Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* apc - Driver implementation for power management functions
0003  * of Aurora Personality Chip (APC) on SPARCstation-4/5 and
0004  * derivatives.
0005  *
0006  * Copyright (c) 2002 Eric Brower (ebrower@usa.net)
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 /* Debugging
0027  * 
0028  * #define APC_DEBUG_LED
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 /* Specify "apc=noidle" on the kernel command line to 
0042  * disable APC CPU standby support.  Certain prototype
0043  * systems (SPARCstation-Fox) do not play well with APC
0044  * CPU idle, so disable this if your system has APC and 
0045  * crashes randomly.
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  * CPU idle callback function
0059  * See .../arch/sparc/kernel/process.c
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     /* Assign power management IDLE handler */
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 /* This driver is not critical to the boot process
0193  * and is easiest to ioremap when SBus is already
0194  * initialized, so we install ourselves thusly:
0195  */
0196 __initcall(apc_init);