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