1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Gemini power management controller 4 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 5 * 6 * Inspired by code from the SL3516 board support by Jason Lee 7 * Inspired by code from Janos Laube <janos.dev@gmail.com> 8 */ 9 #include <linux/of.h> 10 #include <linux/of_platform.h> 11 #include <linux/platform_device.h> 12 #include <linux/pm.h> 13 #include <linux/bitops.h> 14 #include <linux/interrupt.h> 15 #include <linux/io.h> 16 #include <linux/reboot.h> 17 18 #define GEMINI_PWC_ID 0x00010500 19 #define GEMINI_PWC_IDREG 0x00 20 #define GEMINI_PWC_CTRLREG 0x04 21 #define GEMINI_PWC_STATREG 0x08 22 23 #define GEMINI_CTRL_SHUTDOWN BIT(0) 24 #define GEMINI_CTRL_ENABLE BIT(1) 25 #define GEMINI_CTRL_IRQ_CLR BIT(2) 26 27 #define GEMINI_STAT_CIR BIT(4) 28 #define GEMINI_STAT_RTC BIT(5) 29 #define GEMINI_STAT_POWERBUTTON BIT(6) 30 31 struct gemini_powercon { 32 struct device *dev; 33 void __iomem *base; 34 }; 35 36 static irqreturn_t gemini_powerbutton_interrupt(int irq, void *data) 37 { 38 struct gemini_powercon *gpw = data; 39 u32 val; 40 41 /* ACK the IRQ */ 42 val = readl(gpw->base + GEMINI_PWC_CTRLREG); 43 val |= GEMINI_CTRL_IRQ_CLR; 44 writel(val, gpw->base + GEMINI_PWC_CTRLREG); 45 46 val = readl(gpw->base + GEMINI_PWC_STATREG); 47 val &= 0x70U; 48 switch (val) { 49 case GEMINI_STAT_CIR: 50 /* 51 * We do not yet have a driver for the infrared 52 * controller so it can cause spurious poweroff 53 * events. Ignore those for now. 54 */ 55 dev_info(gpw->dev, "infrared poweroff - ignored\n"); 56 break; 57 case GEMINI_STAT_RTC: 58 dev_info(gpw->dev, "RTC poweroff\n"); 59 orderly_poweroff(true); 60 break; 61 case GEMINI_STAT_POWERBUTTON: 62 dev_info(gpw->dev, "poweroff button pressed\n"); 63 orderly_poweroff(true); 64 break; 65 default: 66 dev_info(gpw->dev, "other power management IRQ\n"); 67 break; 68 } 69 70 return IRQ_HANDLED; 71 } 72 73 static int gemini_poweroff(struct sys_off_data *data) 74 { 75 struct gemini_powercon *gpw = data->cb_data; 76 u32 val; 77 78 dev_crit(gpw->dev, "Gemini power off\n"); 79 val = readl(gpw->base + GEMINI_PWC_CTRLREG); 80 val |= GEMINI_CTRL_ENABLE | GEMINI_CTRL_IRQ_CLR; 81 writel(val, gpw->base + GEMINI_PWC_CTRLREG); 82 83 val &= ~GEMINI_CTRL_ENABLE; 84 val |= GEMINI_CTRL_SHUTDOWN; 85 writel(val, gpw->base + GEMINI_PWC_CTRLREG); 86 87 return NOTIFY_DONE; 88 } 89 90 static int gemini_poweroff_probe(struct platform_device *pdev) 91 { 92 struct device *dev = &pdev->dev; 93 struct gemini_powercon *gpw; 94 u32 val; 95 int irq; 96 int ret; 97 98 gpw = devm_kzalloc(dev, sizeof(*gpw), GFP_KERNEL); 99 if (!gpw) 100 return -ENOMEM; 101 102 gpw->base = devm_platform_ioremap_resource(pdev, 0); 103 if (IS_ERR(gpw->base)) 104 return PTR_ERR(gpw->base); 105 106 irq = platform_get_irq(pdev, 0); 107 if (irq < 0) 108 return irq; 109 110 gpw->dev = dev; 111 112 val = readl(gpw->base + GEMINI_PWC_IDREG); 113 val &= 0xFFFFFF00U; 114 if (val != GEMINI_PWC_ID) { 115 dev_err(dev, "wrong power controller ID: %08x\n", 116 val); 117 return -ENODEV; 118 } 119 120 /* 121 * Enable the power controller. This is crucial on Gemini 122 * systems: if this is not done, pressing the power button 123 * will result in unconditional poweroff without any warning. 124 * This makes the kernel handle the poweroff. 125 */ 126 val = readl(gpw->base + GEMINI_PWC_CTRLREG); 127 val |= GEMINI_CTRL_ENABLE; 128 writel(val, gpw->base + GEMINI_PWC_CTRLREG); 129 130 /* Clear the IRQ */ 131 val = readl(gpw->base + GEMINI_PWC_CTRLREG); 132 val |= GEMINI_CTRL_IRQ_CLR; 133 writel(val, gpw->base + GEMINI_PWC_CTRLREG); 134 135 /* Wait for this to clear */ 136 val = readl(gpw->base + GEMINI_PWC_STATREG); 137 while (val & 0x70U) 138 val = readl(gpw->base + GEMINI_PWC_STATREG); 139 140 /* Clear the IRQ again */ 141 val = readl(gpw->base + GEMINI_PWC_CTRLREG); 142 val |= GEMINI_CTRL_IRQ_CLR; 143 writel(val, gpw->base + GEMINI_PWC_CTRLREG); 144 145 ret = devm_request_irq(dev, irq, gemini_powerbutton_interrupt, 0, 146 "poweroff", gpw); 147 if (ret) 148 return ret; 149 150 ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF, 151 SYS_OFF_PRIO_DEFAULT, 152 gemini_poweroff, gpw); 153 if (ret) 154 return ret; 155 156 dev_info(dev, "Gemini poweroff driver registered\n"); 157 158 return 0; 159 } 160 161 static const struct of_device_id gemini_poweroff_of_match[] = { 162 { 163 .compatible = "cortina,gemini-power-controller", 164 }, 165 {} 166 }; 167 168 static struct platform_driver gemini_poweroff_driver = { 169 .probe = gemini_poweroff_probe, 170 .driver = { 171 .name = "gemini-poweroff", 172 .of_match_table = gemini_poweroff_of_match, 173 }, 174 }; 175 builtin_platform_driver(gemini_poweroff_driver); 176