From bfc838f8598eab49d7d3d7557e90a7a0ee9b4464 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Oct 2020 20:53:21 +0300 Subject: [PATCH 01/12] drm/gma500: Convert to use new SCU IPC API Convert the GMA500 driver to use the new SCU IPC API. This allows us to get rid of the duplicate PMC IPC implementation which is now covered in SCU IPC driver. Signed-off-by: Andy Shevchenko Acked-by: Patrik Jakobsson Acked-by: Linus Walleij --- drivers/gpu/drm/gma500/Kconfig | 1 + drivers/gpu/drm/gma500/mdfld_device.c | 2 -- drivers/gpu/drm/gma500/mdfld_dsi_output.c | 2 -- drivers/gpu/drm/gma500/mdfld_output.c | 8 ++++++-- drivers/gpu/drm/gma500/oaktrail_device.c | 3 --- drivers/gpu/drm/gma500/psb_drv.h | 3 +++ drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c | 12 +++++++----- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index 0e23c93a1094..1ef2cda5b5c2 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -30,6 +30,7 @@ config DRM_GMA3600 config DRM_MEDFIELD bool "Intel Medfield support (Experimental)" depends on DRM_GMA500 && X86_INTEL_MID + select INTEL_SCU_IPC help Say yes to include support for the Intel Medfield platform. diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c index b83d59b21de5..12193e591327 100644 --- a/drivers/gpu/drm/gma500/mdfld_device.c +++ b/drivers/gpu/drm/gma500/mdfld_device.c @@ -8,8 +8,6 @@ #include #include -#include - #include "mdfld_dsi_output.h" #include "mdfld_output.h" #include "mid_bios.h" diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c index 4aab76613bd9..38ec49b71499 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c @@ -30,8 +30,6 @@ #include #include -#include - #include "mdfld_dsi_dpi.h" #include "mdfld_dsi_output.h" #include "mdfld_dsi_pkg_sender.h" diff --git a/drivers/gpu/drm/gma500/mdfld_output.c b/drivers/gpu/drm/gma500/mdfld_output.c index c95966bb0c96..518417f49be8 100644 --- a/drivers/gpu/drm/gma500/mdfld_output.c +++ b/drivers/gpu/drm/gma500/mdfld_output.c @@ -25,6 +25,8 @@ * Scott Rowe */ +#include + #include "mdfld_output.h" #include "mdfld_dsi_dpi.h" #include "mdfld_dsi_output.h" @@ -58,11 +60,14 @@ static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe, } } - int mdfld_output_init(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; + dev_priv->scu = devm_intel_scu_ipc_dev_get(&dev->pdev->dev); + if (!dev_priv->scu) + return -EPROBE_DEFER; + /* FIXME: hardcoded for now */ dev_priv->mdfld_panel_id = TC35876X; /* MIPI panel 1 */ @@ -71,4 +76,3 @@ int mdfld_output_init(struct drm_device *dev) mdfld_init_panel(dev, 1, HDMI); return 0; } - diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c index 8754290b0e23..0c1a66b20f27 100644 --- a/drivers/gpu/drm/gma500/oaktrail_device.c +++ b/drivers/gpu/drm/gma500/oaktrail_device.c @@ -10,9 +10,6 @@ #include #include -#include -#include - #include #include "intel_bios.h" diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 5b7f7a312d53..938efdddc27c 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -428,6 +428,8 @@ struct psb_ops; #define PSB_NUM_PIPE 3 +struct intel_scu_ipc_dev; + struct drm_psb_private { struct drm_device *dev; struct pci_dev *aux_pdev; /* Currently only used by mrst */ @@ -567,6 +569,7 @@ struct drm_psb_private { * Used for modifying backlight from * xrandr -- consider removing and using HAL instead */ + struct intel_scu_ipc_dev *scu; struct backlight_device *backlight_device; struct drm_property *backlight_property; bool backlight_enabled; diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c index e5bdd99ad453..7d012db6352b 100644 --- a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c +++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c @@ -444,6 +444,7 @@ static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f) static void tc35876x_brightness_init(struct drm_device *dev) { + struct drm_psb_private *dev_priv = dev->dev_private; int ret; u8 pwmctrl; u16 clkdiv; @@ -451,23 +452,23 @@ static void tc35876x_brightness_init(struct drm_device *dev) /* Make sure the PWM reference is the 19.2 MHz system clock. Read first * instead of setting directly to catch potential conflicts between PWM * users. */ - ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl); + ret = intel_scu_ipc_dev_ioread8(dev_priv->scu, GPIOPWMCTRL, &pwmctrl); if (ret || pwmctrl != 0x01) { if (ret) dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n"); else dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl); - ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01); + ret = intel_scu_ipc_dev_iowrite8(dev_priv->scu, GPIOPWMCTRL, 0x01); if (ret) dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n"); } clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY); - ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff); + ret = intel_scu_ipc_dev_iowrite8(dev_priv->scu, PWM0CLKDIV1, (clkdiv >> 8) & 0xff); if (!ret) - ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff); + ret = intel_scu_ipc_dev_iowrite8(dev_priv->scu, PWM0CLKDIV0, clkdiv & 0xff); if (ret) dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n"); @@ -480,6 +481,7 @@ static void tc35876x_brightness_init(struct drm_device *dev) void tc35876x_brightness_control(struct drm_device *dev, int level) { + struct drm_psb_private *dev_priv = dev->dev_private; int ret; u8 duty_val; u8 panel_duty_val; @@ -495,7 +497,7 @@ void tc35876x_brightness_control(struct drm_device *dev, int level) panel_duty_val = (2 * level - 100) * 0xA9 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56; - ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val); + ret = intel_scu_ipc_dev_iowrite8(dev_priv->scu, PWM0DUTYCYCLE, duty_val); if (ret) dev_err(&tc35876x_client->dev, "%s: ipc write fail\n", __func__); From 25ded39ad064b06757d00609c36c85ab2312a94b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Oct 2020 21:54:00 +0300 Subject: [PATCH 02/12] drm/gma500: Get rid of duplicate NULL checks Since GPIOs are optional we don't need to repeat checks that are done in the GPIO API. Remove them for good. Signed-off-by: Andy Shevchenko Acked-by: Patrik Jakobsson Acked-by: Linus Walleij --- drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c index 7d012db6352b..3dab94463656 100644 --- a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c +++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c @@ -518,11 +518,9 @@ void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev) dev_dbg(&tc35876x_client->dev, "%s\n", __func__); - if (bridge_bl_enable) - gpiod_set_value_cansleep(bridge_bl_enable, 0); + gpiod_set_value_cansleep(bridge_bl_enable, 0); - if (backlight_voltage) - gpiod_set_value_cansleep(backlight_voltage, 0); + gpiod_set_value_cansleep(backlight_voltage, 0); } void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) @@ -567,8 +565,7 @@ void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) "i2c write failed (%d)\n", ret); } - if (bridge_bl_enable) - gpiod_set_value_cansleep(bridge_bl_enable, 1); + gpiod_set_value_cansleep(bridge_bl_enable, 1); tc35876x_brightness_control(dev, dev_priv->brightness_adjusted); } @@ -642,20 +639,17 @@ static int tc35876x_bridge_probe(struct i2c_client *client, bridge_reset = devm_gpiod_get_optional(&client->dev, "bridge-reset", GPIOD_OUT_LOW); if (IS_ERR(bridge_reset)) return PTR_ERR(bridge_reset); - if (bridge_reset) - gpiod_set_consumer_name(bridge_reset, "tc35876x bridge reset"); + gpiod_set_consumer_name(bridge_reset, "tc35876x bridge reset"); bridge_bl_enable = devm_gpiod_get_optional(&client->dev, "bl-en", GPIOD_OUT_LOW); if (IS_ERR(bridge_bl_enable)) return PTR_ERR(bridge_bl_enable); - if (bridge_bl_enable) - gpiod_set_consumer_name(bridge_bl_enable, "tc35876x panel bl en"); + gpiod_set_consumer_name(bridge_bl_enable, "tc35876x panel bl en"); backlight_voltage = devm_gpiod_get_optional(&client->dev, "vadd", GPIOD_OUT_LOW); if (IS_ERR(backlight_voltage)) return PTR_ERR(backlight_voltage); - if (backlight_voltage) - gpiod_set_consumer_name(backlight_voltage, "tc35876x panel vadd"); + gpiod_set_consumer_name(backlight_voltage, "tc35876x panel vadd"); tc35876x_client = client; From 5f7582aa2d3c2ea0a9c9be17bcb53d29c0417ae5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Nov 2019 16:57:30 +0200 Subject: [PATCH 03/12] gpio: intel-mid: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Moreover this code duplicates gpio-pxa since the IP has been derived from XScale implementation. If anybody wants to resurrect this it has to be part of gpio-pxa.c. Signed-off-by: Andy Shevchenko Acked-by: Linus Walleij --- MAINTAINERS | 1 - drivers/gpio/Kconfig | 7 - drivers/gpio/Makefile | 1 - drivers/gpio/TODO | 2 +- drivers/gpio/gpio-intel-mid.c | 414 ---------------------------------- 5 files changed, 1 insertion(+), 424 deletions(-) delete mode 100644 drivers/gpio/gpio-intel-mid.c diff --git a/MAINTAINERS b/MAINTAINERS index 546aa66428c9..92074cba9dcc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8940,7 +8940,6 @@ L: linux-gpio@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git F: drivers/gpio/gpio-ich.c -F: drivers/gpio/gpio-intel-mid.c F: drivers/gpio/gpio-merrifield.c F: drivers/gpio/gpio-ml-ioh.c F: drivers/gpio/gpio-pch.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c70f46e80a3b..6d123cb0bd9c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1451,13 +1451,6 @@ config GPIO_BT8XX If unsure, say N. -config GPIO_INTEL_MID - bool "Intel MID GPIO support" - depends on X86_INTEL_MID - select GPIOLIB_IRQCHIP - help - Say Y here to support Intel MID GPIO. - config GPIO_MERRIFIELD tristate "Intel Merrifield GPIO support" depends on X86_INTEL_MID diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 35e3b6026665..a2106d667fb3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -67,7 +67,6 @@ obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o -obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT87) += gpio-it87.o obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 0229fa79499e..b8b1473a5b1e 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -101,7 +101,7 @@ for a few GPIOs. Those should stay where they are. At the same time it makes sense to get rid of code duplication in existing or new coming drivers. For example, gpio-ml-ioh should be incorporated into -gpio-pch. In similar way gpio-intel-mid into gpio-pxa. +gpio-pch. Generic MMIO GPIO diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c deleted file mode 100644 index 86a10c808ef6..000000000000 --- a/drivers/gpio/gpio-intel-mid.c +++ /dev/null @@ -1,414 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel MID GPIO driver - * - * Copyright (c) 2008-2014,2016 Intel Corporation. - */ - -/* Supports: - * Moorestown platform Langwell chip. - * Medfield platform Penwell chip. - * Clovertrail platform Cloverview chip. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) -#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) - -/* - * Langwell chip has 64 pins and thus there are 2 32bit registers to control - * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit - * registers to control them, so we only define the order here instead of a - * structure, to get a bit offset for a pin (use GPDR as an example): - * - * nreg = ngpio / 32; - * reg = offset / 32; - * bit = offset % 32; - * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; - * - * so the bit of reg_addr is to control pin offset's GPDR feature -*/ - -enum GPIO_REG { - GPLR = 0, /* pin level read-only */ - GPDR, /* pin direction */ - GPSR, /* pin set */ - GPCR, /* pin clear */ - GRER, /* rising edge detect */ - GFER, /* falling edge detect */ - GEDR, /* edge detect result */ - GAFR, /* alt function */ -}; - -/* intel_mid gpio driver data */ -struct intel_mid_gpio_ddata { - u16 ngpio; /* number of gpio pins */ - u32 chip_irq_type; /* chip interrupt type */ -}; - -struct intel_mid_gpio { - struct gpio_chip chip; - void __iomem *reg_base; - spinlock_t lock; - struct pci_dev *pdev; -}; - -static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 32; - - return priv->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 16; - - return priv->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static int intel_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); - u32 value = readl(gafr); - int shift = (offset % 16) << 1, af = (value >> shift) & 3; - - if (af) { - value &= ~(3 << shift); - writel(value, gafr); - } - return 0; -} - -static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gplr = gpio_reg(chip, offset, GPLR); - - return !!(readl(gplr) & BIT(offset % 32)); -} - -static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - void __iomem *gpsr, *gpcr; - - if (value) { - gpsr = gpio_reg(chip, offset, GPSR); - writel(BIT(offset % 32), gpsr); - } else { - gpcr = gpio_reg(chip, offset, GPCR); - writel(BIT(offset % 32), gpcr); - } -} - -static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - u32 value; - unsigned long flags; - - if (priv->pdev) - pm_runtime_get(&priv->pdev->dev); - - spin_lock_irqsave(&priv->lock, flags); - value = readl(gpdr); - value &= ~BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->pdev) - pm_runtime_put(&priv->pdev->dev); - - return 0; -} - -static int intel_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - unsigned long flags; - - intel_gpio_set(chip, offset, value); - - if (priv->pdev) - pm_runtime_get(&priv->pdev->dev); - - spin_lock_irqsave(&priv->lock, flags); - value = readl(gpdr); - value |= BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->pdev) - pm_runtime_put(&priv->pdev->dev); - - return 0; -} - -static int intel_mid_irq_type(struct irq_data *d, unsigned type) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct intel_mid_gpio *priv = gpiochip_get_data(gc); - u32 gpio = irqd_to_hwirq(d); - unsigned long flags; - u32 value; - void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); - void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); - - if (gpio >= priv->chip.ngpio) - return -EINVAL; - - if (priv->pdev) - pm_runtime_get(&priv->pdev->dev); - - spin_lock_irqsave(&priv->lock, flags); - if (type & IRQ_TYPE_EDGE_RISING) - value = readl(grer) | BIT(gpio % 32); - else - value = readl(grer) & (~BIT(gpio % 32)); - writel(value, grer); - - if (type & IRQ_TYPE_EDGE_FALLING) - value = readl(gfer) | BIT(gpio % 32); - else - value = readl(gfer) & (~BIT(gpio % 32)); - writel(value, gfer); - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->pdev) - pm_runtime_put(&priv->pdev->dev); - - return 0; -} - -static void intel_mid_irq_unmask(struct irq_data *d) -{ -} - -static void intel_mid_irq_mask(struct irq_data *d) -{ -} - -static struct irq_chip intel_mid_irqchip = { - .name = "INTEL_MID-GPIO", - .irq_mask = intel_mid_irq_mask, - .irq_unmask = intel_mid_irq_unmask, - .irq_set_type = intel_mid_irq_type, -}; - -static const struct intel_mid_gpio_ddata gpio_lincroft = { - .ngpio = 64, -}; - -static const struct intel_mid_gpio_ddata gpio_penwell_aon = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, -}; - -static const struct intel_mid_gpio_ddata gpio_penwell_core = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, -}; - -static const struct intel_mid_gpio_ddata gpio_cloverview_aon = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE | INTEL_MID_IRQ_TYPE_LEVEL, -}; - -static const struct intel_mid_gpio_ddata gpio_cloverview_core = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, -}; - -static const struct pci_device_id intel_gpio_ids[] = { - { - /* Lincroft */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), - .driver_data = (kernel_ulong_t)&gpio_lincroft, - }, - { - /* Penwell AON */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), - .driver_data = (kernel_ulong_t)&gpio_penwell_aon, - }, - { - /* Penwell Core */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), - .driver_data = (kernel_ulong_t)&gpio_penwell_core, - }, - { - /* Cloverview Aon */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), - .driver_data = (kernel_ulong_t)&gpio_cloverview_aon, - }, - { - /* Cloverview Core */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), - .driver_data = (kernel_ulong_t)&gpio_cloverview_core, - }, - { } -}; - -static void intel_mid_irq_handler(struct irq_desc *desc) -{ - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct intel_mid_gpio *priv = gpiochip_get_data(gc); - struct irq_data *data = irq_desc_get_irq_data(desc); - struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, gpio, mask; - unsigned long pending; - void __iomem *gedr; - - /* check GPIO controller to check which pin triggered the interrupt */ - for (base = 0; base < priv->chip.ngpio; base += 32) { - gedr = gpio_reg(&priv->chip, base, GEDR); - while ((pending = readl(gedr))) { - gpio = __ffs(pending); - mask = BIT(gpio); - /* Clear before handling so we can't lose an edge */ - writel(mask, gedr); - generic_handle_irq(irq_find_mapping(gc->irq.domain, - base + gpio)); - } - } - - chip->irq_eoi(data); -} - -static int intel_mid_irq_init_hw(struct gpio_chip *chip) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - void __iomem *reg; - unsigned base; - - for (base = 0; base < priv->chip.ngpio; base += 32) { - /* Clear the rising-edge detect register */ - reg = gpio_reg(&priv->chip, base, GRER); - writel(0, reg); - /* Clear the falling-edge detect register */ - reg = gpio_reg(&priv->chip, base, GFER); - writel(0, reg); - /* Clear the edge detect status register */ - reg = gpio_reg(&priv->chip, base, GEDR); - writel(~0, reg); - } - - return 0; -} - -static int __maybe_unused intel_gpio_runtime_idle(struct device *dev) -{ - int err = pm_schedule_suspend(dev, 500); - return err ?: -EBUSY; -} - -static const struct dev_pm_ops intel_gpio_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle) -}; - -static int intel_gpio_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *base; - struct intel_mid_gpio *priv; - u32 gpio_base; - u32 irq_base; - int retval; - struct gpio_irq_chip *girq; - struct intel_mid_gpio_ddata *ddata = - (struct intel_mid_gpio_ddata *)id->driver_data; - - retval = pcim_enable_device(pdev); - if (retval) - return retval; - - retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); - if (retval) { - dev_err(&pdev->dev, "I/O memory mapping error\n"); - return retval; - } - - base = pcim_iomap_table(pdev)[1]; - - irq_base = readl(base); - gpio_base = readl(sizeof(u32) + base); - - /* release the IO mapping, since we already get the info from bar1 */ - pcim_iounmap_regions(pdev, 1 << 1); - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->reg_base = pcim_iomap_table(pdev)[0]; - priv->chip.label = dev_name(&pdev->dev); - priv->chip.parent = &pdev->dev; - priv->chip.request = intel_gpio_request; - priv->chip.direction_input = intel_gpio_direction_input; - priv->chip.direction_output = intel_gpio_direction_output; - priv->chip.get = intel_gpio_get; - priv->chip.set = intel_gpio_set; - priv->chip.base = gpio_base; - priv->chip.ngpio = ddata->ngpio; - priv->chip.can_sleep = false; - priv->pdev = pdev; - - spin_lock_init(&priv->lock); - - girq = &priv->chip.irq; - girq->chip = &intel_mid_irqchip; - girq->init_hw = intel_mid_irq_init_hw; - girq->parent_handler = intel_mid_irq_handler; - girq->num_parents = 1; - girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, - sizeof(*girq->parents), - GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - girq->parents[0] = pdev->irq; - girq->first = irq_base; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_simple_irq; - - pci_set_drvdata(pdev, priv); - - retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); - if (retval) { - dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); - return retval; - } - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; -} - -static struct pci_driver intel_gpio_driver = { - .name = "intel_mid_gpio", - .id_table = intel_gpio_ids, - .probe = intel_gpio_probe, - .driver = { - .pm = &intel_gpio_pm_ops, - }, -}; - -builtin_pci_driver(intel_gpio_driver); From aee25798acf00978a2d9d39ae8b2c2353757d01d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Nov 2019 16:57:30 +0200 Subject: [PATCH 04/12] gpio: msic: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Signed-off-by: Andy Shevchenko Acked-by: Linus Walleij --- MAINTAINERS | 1 - drivers/gpio/Kconfig | 7 - drivers/gpio/gpio-msic.c | 314 --------------------------------------- 3 files changed, 322 deletions(-) delete mode 100644 drivers/gpio/gpio-msic.c diff --git a/MAINTAINERS b/MAINTAINERS index 92074cba9dcc..a5f161c9a059 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9098,7 +9098,6 @@ M: Andy Shevchenko S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git F: drivers/gpio/gpio-*cove.c -F: drivers/gpio/gpio-msic.c INTEL PMIC MULTIFUNCTION DEVICE DRIVERS M: Andy Shevchenko diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6d123cb0bd9c..a6987ff28d7c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1249,13 +1249,6 @@ config GPIO_MAX77650 GPIO driver for MAX77650/77651 PMIC from Maxim Semiconductor. These chips have a single pin that can be configured as GPIO. -config GPIO_MSIC - bool "Intel MSIC mixed signal gpio support" - depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC - help - Enable support for GPIO on intel MSIC controllers found in - intel MID devices - config GPIO_PALMAS bool "TI PALMAS series PMICs GPIO" depends on MFD_PALMAS diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c deleted file mode 100644 index 7e3c96e4ab2c..000000000000 --- a/drivers/gpio/gpio-msic.c +++ /dev/null @@ -1,314 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel Medfield MSIC GPIO driver> - * Copyright (c) 2011, Intel Corporation. - * - * Author: Mathias Nyman - * Based on intel_pmic_gpio.c - */ - -#include -#include -#include -#include -#include -#include -#include - -/* the offset for the mapping of global gpio pin to irq */ -#define MSIC_GPIO_IRQ_OFFSET 0x100 - -#define MSIC_GPIO_DIR_IN 0 -#define MSIC_GPIO_DIR_OUT BIT(5) -#define MSIC_GPIO_TRIG_FALL BIT(1) -#define MSIC_GPIO_TRIG_RISE BIT(2) - -/* masks for msic gpio output GPIOxxxxCTLO registers */ -#define MSIC_GPIO_DIR_MASK BIT(5) -#define MSIC_GPIO_DRV_MASK BIT(4) -#define MSIC_GPIO_REN_MASK BIT(3) -#define MSIC_GPIO_RVAL_MASK (BIT(2) | BIT(1)) -#define MSIC_GPIO_DOUT_MASK BIT(0) - -/* masks for msic gpio input GPIOxxxxCTLI registers */ -#define MSIC_GPIO_GLBYP_MASK BIT(5) -#define MSIC_GPIO_DBNC_MASK (BIT(4) | BIT(3)) -#define MSIC_GPIO_INTCNT_MASK (BIT(2) | BIT(1)) -#define MSIC_GPIO_DIN_MASK BIT(0) - -#define MSIC_NUM_GPIO 24 - -struct msic_gpio { - struct platform_device *pdev; - struct mutex buslock; - struct gpio_chip chip; - int irq; - unsigned irq_base; - unsigned long trig_change_mask; - unsigned trig_type; -}; - -/* - * MSIC has 24 gpios, 16 low voltage (1.2-1.8v) and 8 high voltage (3v). - * Both the high and low voltage gpios are divided in two banks. - * GPIOs are numbered with GPIO0LV0 as gpio_base in the following order: - * GPIO0LV0..GPIO0LV7: low voltage, bank 0, gpio_base - * GPIO1LV0..GPIO1LV7: low voltage, bank 1, gpio_base + 8 - * GPIO0HV0..GPIO0HV3: high voltage, bank 0, gpio_base + 16 - * GPIO1HV0..GPIO1HV3: high voltage, bank 1, gpio_base + 20 - */ - -static int msic_gpio_to_ireg(unsigned offset) -{ - if (offset >= MSIC_NUM_GPIO) - return -EINVAL; - - if (offset < 8) - return INTEL_MSIC_GPIO0LV0CTLI - offset; - if (offset < 16) - return INTEL_MSIC_GPIO1LV0CTLI - offset + 8; - if (offset < 20) - return INTEL_MSIC_GPIO0HV0CTLI - offset + 16; - - return INTEL_MSIC_GPIO1HV0CTLI - offset + 20; -} - -static int msic_gpio_to_oreg(unsigned offset) -{ - if (offset >= MSIC_NUM_GPIO) - return -EINVAL; - - if (offset < 8) - return INTEL_MSIC_GPIO0LV0CTLO - offset; - if (offset < 16) - return INTEL_MSIC_GPIO1LV0CTLO - offset + 8; - if (offset < 20) - return INTEL_MSIC_GPIO0HV0CTLO - offset + 16; - - return INTEL_MSIC_GPIO1HV0CTLO - offset + 20; -} - -static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - int reg; - - reg = msic_gpio_to_oreg(offset); - if (reg < 0) - return reg; - - return intel_msic_reg_update(reg, MSIC_GPIO_DIR_IN, MSIC_GPIO_DIR_MASK); -} - -static int msic_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - int reg; - unsigned mask; - - value = (!!value) | MSIC_GPIO_DIR_OUT; - mask = MSIC_GPIO_DIR_MASK | MSIC_GPIO_DOUT_MASK; - - reg = msic_gpio_to_oreg(offset); - if (reg < 0) - return reg; - - return intel_msic_reg_update(reg, value, mask); -} - -static int msic_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - u8 r; - int ret; - int reg; - - reg = msic_gpio_to_ireg(offset); - if (reg < 0) - return reg; - - ret = intel_msic_reg_read(reg, &r); - if (ret < 0) - return ret; - - return !!(r & MSIC_GPIO_DIN_MASK); -} - -static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - int reg; - - reg = msic_gpio_to_oreg(offset); - if (reg < 0) - return; - - intel_msic_reg_update(reg, !!value , MSIC_GPIO_DOUT_MASK); -} - -/* - * This is called from genirq with mg->buslock locked and - * irq_desc->lock held. We can not access the scu bus here, so we - * store the change and update in the bus_sync_unlock() function below - */ -static int msic_irq_type(struct irq_data *data, unsigned type) -{ - struct msic_gpio *mg = irq_data_get_irq_chip_data(data); - u32 gpio = data->irq - mg->irq_base; - - if (gpio >= mg->chip.ngpio) - return -EINVAL; - - /* mark for which gpio the trigger changed, protected by buslock */ - mg->trig_change_mask |= (1 << gpio); - mg->trig_type = type; - - return 0; -} - -static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct msic_gpio *mg = gpiochip_get_data(chip); - return mg->irq_base + offset; -} - -static void msic_bus_lock(struct irq_data *data) -{ - struct msic_gpio *mg = irq_data_get_irq_chip_data(data); - mutex_lock(&mg->buslock); -} - -static void msic_bus_sync_unlock(struct irq_data *data) -{ - struct msic_gpio *mg = irq_data_get_irq_chip_data(data); - int offset; - int reg; - u8 trig = 0; - - /* We can only get one change at a time as the buslock covers the - entire transaction. The irq_desc->lock is dropped before we are - called but that is fine */ - if (mg->trig_change_mask) { - offset = __ffs(mg->trig_change_mask); - - reg = msic_gpio_to_ireg(offset); - if (reg < 0) - goto out; - - if (mg->trig_type & IRQ_TYPE_EDGE_RISING) - trig |= MSIC_GPIO_TRIG_RISE; - if (mg->trig_type & IRQ_TYPE_EDGE_FALLING) - trig |= MSIC_GPIO_TRIG_FALL; - - intel_msic_reg_update(reg, trig, MSIC_GPIO_INTCNT_MASK); - mg->trig_change_mask = 0; - } -out: - mutex_unlock(&mg->buslock); -} - -/* Firmware does all the masking and unmasking for us, no masking here. */ -static void msic_irq_unmask(struct irq_data *data) { } - -static void msic_irq_mask(struct irq_data *data) { } - -static struct irq_chip msic_irqchip = { - .name = "MSIC-GPIO", - .irq_mask = msic_irq_mask, - .irq_unmask = msic_irq_unmask, - .irq_set_type = msic_irq_type, - .irq_bus_lock = msic_bus_lock, - .irq_bus_sync_unlock = msic_bus_sync_unlock, -}; - -static void msic_gpio_irq_handler(struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct msic_gpio *mg = irq_data_get_irq_handler_data(data); - struct irq_chip *chip = irq_data_get_irq_chip(data); - struct intel_msic *msic = pdev_to_intel_msic(mg->pdev); - unsigned long pending; - int i; - int bitnr; - u8 pin; - - for (i = 0; i < (mg->chip.ngpio / BITS_PER_BYTE); i++) { - intel_msic_irq_read(msic, INTEL_MSIC_GPIO0LVIRQ + i, &pin); - pending = pin; - - for_each_set_bit(bitnr, &pending, BITS_PER_BYTE) - generic_handle_irq(mg->irq_base + i * BITS_PER_BYTE + bitnr); - } - chip->irq_eoi(data); -} - -static int platform_msic_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct intel_msic_gpio_pdata *pdata = dev_get_platdata(dev); - struct msic_gpio *mg; - int irq = platform_get_irq(pdev, 0); - int retval; - int i; - - if (irq < 0) { - dev_err(dev, "no IRQ line: %d\n", irq); - return irq; - } - - if (!pdata || !pdata->gpio_base) { - dev_err(dev, "incorrect or missing platform data\n"); - return -EINVAL; - } - - mg = kzalloc(sizeof(*mg), GFP_KERNEL); - if (!mg) - return -ENOMEM; - - dev_set_drvdata(dev, mg); - - mg->pdev = pdev; - mg->irq = irq; - mg->irq_base = pdata->gpio_base + MSIC_GPIO_IRQ_OFFSET; - mg->chip.label = "msic_gpio"; - mg->chip.direction_input = msic_gpio_direction_input; - mg->chip.direction_output = msic_gpio_direction_output; - mg->chip.get = msic_gpio_get; - mg->chip.set = msic_gpio_set; - mg->chip.to_irq = msic_gpio_to_irq; - mg->chip.base = pdata->gpio_base; - mg->chip.ngpio = MSIC_NUM_GPIO; - mg->chip.can_sleep = true; - mg->chip.parent = dev; - - mutex_init(&mg->buslock); - - retval = gpiochip_add_data(&mg->chip, mg); - if (retval) { - dev_err(dev, "Adding MSIC gpio chip failed\n"); - goto err; - } - - for (i = 0; i < mg->chip.ngpio; i++) { - irq_set_chip_data(i + mg->irq_base, mg); - irq_set_chip_and_handler(i + mg->irq_base, - &msic_irqchip, - handle_simple_irq); - } - irq_set_chained_handler_and_data(mg->irq, msic_gpio_irq_handler, mg); - - return 0; -err: - kfree(mg); - return retval; -} - -static struct platform_driver platform_msic_gpio_driver = { - .driver = { - .name = "msic_gpio", - }, - .probe = platform_msic_gpio_probe, -}; - -static int __init platform_msic_gpio_init(void) -{ - return platform_driver_register(&platform_msic_gpio_driver); -} -subsys_initcall(platform_msic_gpio_init); From bbb284c007b3be59aed94a202a20c1be3e942caf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Aug 2020 12:47:11 +0300 Subject: [PATCH 05/12] platform/x86: intel_mid_thermal: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Acked-by: Linus Walleij --- drivers/platform/x86/Kconfig | 7 - drivers/platform/x86/Makefile | 1 - drivers/platform/x86/intel_mid_thermal.c | 560 ----------------------- 3 files changed, 568 deletions(-) delete mode 100644 drivers/platform/x86/intel_mid_thermal.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 91e6176cdfbd..3ba680af3ef5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1327,13 +1327,6 @@ config INTEL_CHTDC_TI_PWRBTN To compile this driver as a module, choose M here: the module will be called intel_chtdc_ti_pwrbtn. -config INTEL_MFLD_THERMAL - tristate "Thermal driver for Intel Medfield platform" - depends on MFD_INTEL_MSIC && THERMAL - help - Say Y here to enable thermal driver support for the Intel Medfield - platform. - config INTEL_MID_POWER_BUTTON tristate "power button driver for Intel MID platforms" depends on INTEL_SCU && INPUT diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 581475f59819..6fb57502b59a 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -137,7 +137,6 @@ obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency.o # Intel PMIC / PMC / P-Unit devices obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o -obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c deleted file mode 100644 index f12f4e7bd971..000000000000 --- a/drivers/platform/x86/intel_mid_thermal.c +++ /dev/null @@ -1,560 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel MID platform thermal driver - * - * Copyright (C) 2011 Intel Corporation - * - * Author: Durgadoss R - */ - -#define pr_fmt(fmt) "intel_mid_thermal: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Number of thermal sensors */ -#define MSIC_THERMAL_SENSORS 4 - -/* ADC1 - thermal registers */ -#define MSIC_ADC_ENBL 0x10 -#define MSIC_ADC_START 0x08 - -#define MSIC_ADCTHERM_ENBL 0x04 -#define MSIC_ADCRRDATA_ENBL 0x05 -#define MSIC_CHANL_MASK_VAL 0x0F - -#define MSIC_STOPBIT_MASK 16 -#define MSIC_ADCTHERM_MASK 4 -/* Number of ADC channels */ -#define ADC_CHANLS_MAX 15 -#define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS) - -/* ADC channel code values */ -#define SKIN_SENSOR0_CODE 0x08 -#define SKIN_SENSOR1_CODE 0x09 -#define SYS_SENSOR_CODE 0x0A -#define MSIC_DIE_SENSOR_CODE 0x03 - -#define SKIN_THERM_SENSOR0 0 -#define SKIN_THERM_SENSOR1 1 -#define SYS_THERM_SENSOR2 2 -#define MSIC_DIE_THERM_SENSOR3 3 - -/* ADC code range */ -#define ADC_MAX 977 -#define ADC_MIN 162 -#define ADC_VAL0C 887 -#define ADC_VAL20C 720 -#define ADC_VAL40C 508 -#define ADC_VAL60C 315 - -/* ADC base addresses */ -#define ADC_CHNL_START_ADDR INTEL_MSIC_ADC1ADDR0 /* increments by 1 */ -#define ADC_DATA_START_ADDR INTEL_MSIC_ADC1SNS0H /* increments by 2 */ - -/* MSIC die attributes */ -#define MSIC_DIE_ADC_MIN 488 -#define MSIC_DIE_ADC_MAX 1004 - -/* This holds the address of the first free ADC channel, - * among the 15 channels - */ -static int channel_index; - -struct platform_info { - struct platform_device *pdev; - struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS]; -}; - -struct thermal_device_info { - unsigned int chnl_addr; - int direct; - /* This holds the current temperature in millidegree celsius */ - long curr_temp; -}; - -/** - * to_msic_die_temp - converts adc_val to msic_die temperature - * @adc_val: ADC value to be converted - * - * Can sleep - */ -static int to_msic_die_temp(uint16_t adc_val) -{ - return (368 * (adc_val) / 1000) - 220; -} - -/** - * is_valid_adc - checks whether the adc code is within the defined range - * @min: minimum value for the sensor - * @max: maximum value for the sensor - * - * Can sleep - */ -static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max) -{ - return (adc_val >= min) && (adc_val <= max); -} - -/** - * adc_to_temp - converts the ADC code to temperature in C - * @direct: true if ths channel is direct index - * @adc_val: the adc_val that needs to be converted - * @tp: temperature return value - * - * Linear approximation is used to covert the skin adc value into temperature. - * This technique is used to avoid very long look-up table to get - * the appropriate temp value from ADC value. - * The adc code vs sensor temp curve is split into five parts - * to achieve very close approximate temp value with less than - * 0.5C error - */ -static int adc_to_temp(int direct, uint16_t adc_val, int *tp) -{ - int temp; - - /* Direct conversion for die temperature */ - if (direct) { - if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) { - *tp = to_msic_die_temp(adc_val) * 1000; - return 0; - } - return -ERANGE; - } - - if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX)) - return -ERANGE; - - /* Linear approximation for skin temperature */ - if (adc_val > ADC_VAL0C) - temp = 177 - (adc_val/5); - else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C)) - temp = 111 - (adc_val/8); - else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C)) - temp = 92 - (adc_val/10); - else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C)) - temp = 91 - (adc_val/10); - else - temp = 112 - (adc_val/6); - - /* Convert temperature in celsius to milli degree celsius */ - *tp = temp * 1000; - return 0; -} - -/** - * mid_read_temp - read sensors for temperature - * @temp: holds the current temperature for the sensor after reading - * - * reads the adc_code from the channel and converts it to real - * temperature. The converted value is stored in temp. - * - * Can sleep - */ -static int mid_read_temp(struct thermal_zone_device *tzd, int *temp) -{ - struct thermal_device_info *td_info = tzd->devdata; - uint16_t adc_val, addr; - uint8_t data = 0; - int ret; - int curr_temp; - - addr = td_info->chnl_addr; - - /* Enable the msic for conversion before reading */ - ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); - if (ret) - return ret; - - /* Re-toggle the RRDATARD bit (temporary workaround) */ - ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCTHERM_ENBL); - if (ret) - return ret; - - /* Read the higher bits of data */ - ret = intel_msic_reg_read(addr, &data); - if (ret) - return ret; - - /* Shift bits to accommodate the lower two data bits */ - adc_val = (data << 2); - addr++; - - ret = intel_msic_reg_read(addr, &data);/* Read lower bits */ - if (ret) - return ret; - - /* Adding lower two bits to the higher bits */ - data &= 03; - adc_val += data; - - /* Convert ADC value to temperature */ - ret = adc_to_temp(td_info->direct, adc_val, &curr_temp); - if (ret == 0) - *temp = td_info->curr_temp = curr_temp; - return ret; -} - -/** - * configure_adc - enables/disables the ADC for conversion - * @val: zero: disables the ADC non-zero:enables the ADC - * - * Enable/Disable the ADC depending on the argument - * - * Can sleep - */ -static int configure_adc(int val) -{ - int ret; - uint8_t data; - - ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data); - if (ret) - return ret; - - if (val) { - /* Enable and start the ADC */ - data |= (MSIC_ADC_ENBL | MSIC_ADC_START); - } else { - /* Just stop the ADC */ - data &= (~MSIC_ADC_START); - } - return intel_msic_reg_write(INTEL_MSIC_ADC1CNTL1, data); -} - -/** - * set_up_therm_channel - enable thermal channel for conversion - * @base_addr: index of free msic ADC channel - * - * Enable all the three channels for conversion - * - * Can sleep - */ -static int set_up_therm_channel(u16 base_addr) -{ - int ret; - - /* Enable all the sensor channels */ - ret = intel_msic_reg_write(base_addr, SKIN_SENSOR0_CODE); - if (ret) - return ret; - - ret = intel_msic_reg_write(base_addr + 1, SKIN_SENSOR1_CODE); - if (ret) - return ret; - - ret = intel_msic_reg_write(base_addr + 2, SYS_SENSOR_CODE); - if (ret) - return ret; - - /* Since this is the last channel, set the stop bit - * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ - ret = intel_msic_reg_write(base_addr + 3, - (MSIC_DIE_SENSOR_CODE | 0x10)); - if (ret) - return ret; - - /* Enable ADC and start it */ - return configure_adc(1); -} - -/** - * reset_stopbit - sets the stop bit to 0 on the given channel - * @addr: address of the channel - * - * Can sleep - */ -static int reset_stopbit(uint16_t addr) -{ - int ret; - uint8_t data; - ret = intel_msic_reg_read(addr, &data); - if (ret) - return ret; - /* Set the stop bit to zero */ - return intel_msic_reg_write(addr, (data & 0xEF)); -} - -/** - * find_free_channel - finds an empty channel for conversion - * - * If the ADC is not enabled then start using 0th channel - * itself. Otherwise find an empty channel by looking for a - * channel in which the stopbit is set to 1. returns the index - * of the first free channel if succeeds or an error code. - * - * Context: can sleep - * - * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc - * code. - */ -static int find_free_channel(void) -{ - int ret; - int i; - uint8_t data; - - /* check whether ADC is enabled */ - ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data); - if (ret) - return ret; - - if ((data & MSIC_ADC_ENBL) == 0) - return 0; - - /* ADC is already enabled; Looking for an empty channel */ - for (i = 0; i < ADC_CHANLS_MAX; i++) { - ret = intel_msic_reg_read(ADC_CHNL_START_ADDR + i, &data); - if (ret) - return ret; - - if (data & MSIC_STOPBIT_MASK) { - ret = i; - break; - } - } - return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; -} - -/** - * mid_initialize_adc - initializing the ADC - * @dev: our device structure - * - * Initialize the ADC for reading thermistor values. Can sleep. - */ -static int mid_initialize_adc(struct device *dev) -{ - u8 data; - u16 base_addr; - int ret; - - /* - * Ensure that adctherm is disabled before we - * initialize the ADC - */ - ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL3, &data); - if (ret) - return ret; - - data &= ~MSIC_ADCTHERM_MASK; - ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, data); - if (ret) - return ret; - - /* Index of the first channel in which the stop bit is set */ - channel_index = find_free_channel(); - if (channel_index < 0) { - dev_err(dev, "No free ADC channels"); - return channel_index; - } - - base_addr = ADC_CHNL_START_ADDR + channel_index; - - if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { - /* Reset stop bit for channels other than 0 and 12 */ - ret = reset_stopbit(base_addr); - if (ret) - return ret; - - /* Index of the first free channel */ - base_addr++; - channel_index++; - } - - ret = set_up_therm_channel(base_addr); - if (ret) { - dev_err(dev, "unable to enable ADC"); - return ret; - } - dev_dbg(dev, "ADC initialization successful"); - return ret; -} - -/** - * initialize_sensor - sets default temp and timer ranges - * @index: index of the sensor - * - * Context: can sleep - */ -static struct thermal_device_info *initialize_sensor(int index) -{ - struct thermal_device_info *td_info = - kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL); - - if (!td_info) - return NULL; - - /* Set the base addr of the channel for this sensor */ - td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index); - /* Sensor 3 is direct conversion */ - if (index == 3) - td_info->direct = 1; - return td_info; -} - -#ifdef CONFIG_PM_SLEEP -/** - * mid_thermal_resume - resume routine - * @dev: device structure - * - * mid thermal resume: re-initializes the adc. Can sleep. - */ -static int mid_thermal_resume(struct device *dev) -{ - return mid_initialize_adc(dev); -} - -/** - * mid_thermal_suspend - suspend routine - * @dev: device structure - * - * mid thermal suspend implements the suspend functionality - * by stopping the ADC. Can sleep. - */ -static int mid_thermal_suspend(struct device *dev) -{ - /* - * This just stops the ADC and does not disable it. - * temporary workaround until we have a generic ADC driver. - * If 0 is passed, it disables the ADC. - */ - return configure_adc(0); -} -#endif - -static SIMPLE_DEV_PM_OPS(mid_thermal_pm, - mid_thermal_suspend, mid_thermal_resume); - -/** - * read_curr_temp - reads the current temperature and stores in temp - * @temp: holds the current temperature value after reading - * - * Can sleep - */ -static int read_curr_temp(struct thermal_zone_device *tzd, int *temp) -{ - WARN_ON(tzd == NULL); - return mid_read_temp(tzd, temp); -} - -/* Can't be const */ -static struct thermal_zone_device_ops tzd_ops = { - .get_temp = read_curr_temp, -}; - -/** - * mid_thermal_probe - mfld thermal initialize - * @pdev: platform device structure - * - * mid thermal probe initializes the hardware and registers - * all the sensors with the generic thermal framework. Can sleep. - */ -static int mid_thermal_probe(struct platform_device *pdev) -{ - static char *name[MSIC_THERMAL_SENSORS] = { - "skin0", "skin1", "sys", "msicdie" - }; - - int ret; - int i; - struct platform_info *pinfo; - - pinfo = devm_kzalloc(&pdev->dev, sizeof(struct platform_info), - GFP_KERNEL); - if (!pinfo) - return -ENOMEM; - - /* Initializing the hardware */ - ret = mid_initialize_adc(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "ADC init failed"); - return ret; - } - - /* Register each sensor with the generic thermal framework*/ - for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { - struct thermal_device_info *td_info = initialize_sensor(i); - - if (!td_info) { - ret = -ENOMEM; - goto err; - } - pinfo->tzd[i] = thermal_zone_device_register(name[i], - 0, 0, td_info, &tzd_ops, NULL, 0, 0); - if (IS_ERR(pinfo->tzd[i])) { - kfree(td_info); - ret = PTR_ERR(pinfo->tzd[i]); - goto err; - } - ret = thermal_zone_device_enable(pinfo->tzd[i]); - if (ret) { - kfree(td_info); - thermal_zone_device_unregister(pinfo->tzd[i]); - goto err; - } - } - - pinfo->pdev = pdev; - platform_set_drvdata(pdev, pinfo); - return 0; - -err: - while (--i >= 0) { - kfree(pinfo->tzd[i]->devdata); - thermal_zone_device_unregister(pinfo->tzd[i]); - } - configure_adc(0); - return ret; -} - -/** - * mid_thermal_remove - mfld thermal finalize - * @dev: platform device structure - * - * MLFD thermal remove unregisters all the sensors from the generic - * thermal framework. Can sleep. - */ -static int mid_thermal_remove(struct platform_device *pdev) -{ - int i; - struct platform_info *pinfo = platform_get_drvdata(pdev); - - for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { - kfree(pinfo->tzd[i]->devdata); - thermal_zone_device_unregister(pinfo->tzd[i]); - } - - /* Stop the ADC */ - return configure_adc(0); -} - -#define DRIVER_NAME "msic_thermal" - -static const struct platform_device_id therm_id_table[] = { - { DRIVER_NAME, 1 }, - { } -}; -MODULE_DEVICE_TABLE(platform, therm_id_table); - -static struct platform_driver mid_thermal_driver = { - .driver = { - .name = DRIVER_NAME, - .pm = &mid_thermal_pm, - }, - .probe = mid_thermal_probe, - .remove = mid_thermal_remove, - .id_table = therm_id_table, -}; - -module_platform_driver(mid_thermal_driver); - -MODULE_AUTHOR("Durgadoss R "); -MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver"); -MODULE_LICENSE("GPL v2"); From ae1527948f67d4b8a61f586f792d0971ea44bc92 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Jul 2020 16:42:10 +0300 Subject: [PATCH 06/12] platform/x86: intel_mid_powerbtn: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Acked-by: Linus Walleij --- drivers/platform/x86/Kconfig | 8 - drivers/platform/x86/Makefile | 1 - drivers/platform/x86/intel_mid_powerbtn.c | 233 ---------------------- 3 files changed, 242 deletions(-) delete mode 100644 drivers/platform/x86/intel_mid_powerbtn.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 3ba680af3ef5..4a5798a0ce0c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1327,14 +1327,6 @@ config INTEL_CHTDC_TI_PWRBTN To compile this driver as a module, choose M here: the module will be called intel_chtdc_ti_pwrbtn. -config INTEL_MID_POWER_BUTTON - tristate "power button driver for Intel MID platforms" - depends on INTEL_SCU && INPUT - help - This driver handles the power button on the Intel MID platforms. - - If unsure, say N. - config INTEL_MRFLD_PWRBTN tristate "Intel Merrifield Basin Cove power button driver" depends on INTEL_SOC_PMIC_MRFLD diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 6fb57502b59a..728ccc226a29 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -137,7 +137,6 @@ obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency.o # Intel PMIC / PMC / P-Unit devices obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o -obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o obj-$(CONFIG_INTEL_PMT_CLASS) += intel_pmt_class.o diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c deleted file mode 100644 index df434abbb66f..000000000000 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ /dev/null @@ -1,233 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Power button driver for Intel MID platforms. - * - * Copyright (C) 2010,2017 Intel Corp - * - * Author: Hong Liu - * Author: Andy Shevchenko - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define DRIVER_NAME "msic_power_btn" - -#define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ - -/* - * MSIC document ti_datasheet defines the 1st bit reg 0x21 is used to mask - * power button interrupt - */ -#define MSIC_PWRBTNM (1 << 0) - -/* Intel Tangier */ -#define BCOVE_PB_LEVEL (1 << 4) /* 1 - release, 0 - press */ - -/* Basin Cove PMIC */ -#define BCOVE_PBIRQ 0x02 -#define BCOVE_IRQLVL1MSK 0x0c -#define BCOVE_PBIRQMASK 0x0d -#define BCOVE_PBSTATUS 0x27 - -struct mid_pb_ddata { - struct device *dev; - int irq; - struct input_dev *input; - unsigned short mirqlvl1_addr; - unsigned short pbstat_addr; - u8 pbstat_mask; - struct intel_scu_ipc_dev *scu; - int (*setup)(struct mid_pb_ddata *ddata); -}; - -static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) -{ - struct input_dev *input = ddata->input; - int ret; - u8 pbstat; - - ret = intel_scu_ipc_dev_ioread8(ddata->scu, ddata->pbstat_addr, - &pbstat); - if (ret) - return ret; - - dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat); - - *value = !(pbstat & ddata->pbstat_mask); - return 0; -} - -static int mid_irq_ack(struct mid_pb_ddata *ddata) -{ - return intel_scu_ipc_dev_update(ddata->scu, ddata->mirqlvl1_addr, 0, - MSIC_PWRBTNM); -} - -static int mrfld_setup(struct mid_pb_ddata *ddata) -{ - /* Unmask the PBIRQ and MPBIRQ on Tangier */ - intel_scu_ipc_dev_update(ddata->scu, BCOVE_PBIRQ, 0, MSIC_PWRBTNM); - intel_scu_ipc_dev_update(ddata->scu, BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM); - - return 0; -} - -static irqreturn_t mid_pb_isr(int irq, void *dev_id) -{ - struct mid_pb_ddata *ddata = dev_id; - struct input_dev *input = ddata->input; - int value = 0; - int ret; - - ret = mid_pbstat(ddata, &value); - if (ret < 0) { - dev_err(input->dev.parent, - "Read error %d while reading MSIC_PB_STATUS\n", ret); - } else { - input_event(input, EV_KEY, KEY_POWER, value); - input_sync(input); - } - - mid_irq_ack(ddata); - return IRQ_HANDLED; -} - -static const struct mid_pb_ddata mfld_ddata = { - .mirqlvl1_addr = INTEL_MSIC_IRQLVL1MSK, - .pbstat_addr = INTEL_MSIC_PBSTATUS, - .pbstat_mask = MSIC_PB_LEVEL, -}; - -static const struct mid_pb_ddata mrfld_ddata = { - .mirqlvl1_addr = BCOVE_IRQLVL1MSK, - .pbstat_addr = BCOVE_PBSTATUS, - .pbstat_mask = BCOVE_PB_LEVEL, - .setup = mrfld_setup, -}; - -static const struct x86_cpu_id mid_pb_cpu_ids[] = { - X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_MID, &mfld_ddata), - X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &mrfld_ddata), - {} -}; - -static int mid_pb_probe(struct platform_device *pdev) -{ - const struct x86_cpu_id *id; - struct mid_pb_ddata *ddata; - struct input_dev *input; - int irq = platform_get_irq(pdev, 0); - int error; - - id = x86_match_cpu(mid_pb_cpu_ids); - if (!id) - return -ENODEV; - - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); - return irq; - } - - input = devm_input_allocate_device(&pdev->dev); - if (!input) - return -ENOMEM; - - input->name = pdev->name; - input->phys = "power-button/input0"; - input->id.bustype = BUS_HOST; - input->dev.parent = &pdev->dev; - - input_set_capability(input, EV_KEY, KEY_POWER); - - ddata = devm_kmemdup(&pdev->dev, (void *)id->driver_data, - sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - - ddata->dev = &pdev->dev; - ddata->irq = irq; - ddata->input = input; - - if (ddata->setup) { - error = ddata->setup(ddata); - if (error) - return error; - } - - ddata->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); - if (!ddata->scu) - return -EPROBE_DEFER; - - error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr, - IRQF_ONESHOT, DRIVER_NAME, ddata); - if (error) { - dev_err(&pdev->dev, - "Unable to request irq %d for MID power button\n", irq); - return error; - } - - error = input_register_device(input); - if (error) { - dev_err(&pdev->dev, - "Unable to register input dev, error %d\n", error); - return error; - } - - platform_set_drvdata(pdev, ddata); - - /* - * SCU firmware might send power button interrupts to IA core before - * kernel boots and doesn't get EOI from IA core. The first bit of - * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new - * power interrupt to Android kernel. Unmask the bit when probing - * power button in kernel. - * There is a very narrow race between irq handler and power button - * initialization. The race happens rarely. So we needn't worry - * about it. - */ - error = mid_irq_ack(ddata); - if (error) { - dev_err(&pdev->dev, - "Unable to clear power button interrupt, error: %d\n", - error); - return error; - } - - device_init_wakeup(&pdev->dev, true); - dev_pm_set_wake_irq(&pdev->dev, irq); - - return 0; -} - -static int mid_pb_remove(struct platform_device *pdev) -{ - dev_pm_clear_wake_irq(&pdev->dev); - device_init_wakeup(&pdev->dev, false); - - return 0; -} - -static struct platform_driver mid_pb_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = mid_pb_probe, - .remove = mid_pb_remove, -}; - -module_platform_driver(mid_pb_driver); - -MODULE_AUTHOR("Hong Liu "); -MODULE_DESCRIPTION("Intel MID Power Button Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); From c5158358dffc8c7962f412c2c89fcce4e5fff96f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 18 Nov 2020 12:46:44 +0200 Subject: [PATCH 07/12] rtc: mrst: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Signed-off-by: Andy Shevchenko Acked-by: Alexandre Belloni Acked-by: Linus Walleij --- drivers/rtc/Kconfig | 12 - drivers/rtc/Makefile | 1 - drivers/rtc/rtc-mrst.c | 521 ----------------------------------------- 3 files changed, 534 deletions(-) delete mode 100644 drivers/rtc/rtc-mrst.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6123f9f4fbc9..2a402c10f8f1 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -973,18 +973,6 @@ config RTC_DRV_ALPHA Direct support for the real-time clock found on every Alpha system, specifically MC146818 compatibles. If in doubt, say Y. -config RTC_DRV_VRTC - tristate "Virtual RTC for Intel MID platforms" - depends on X86_INTEL_MID - default y if X86_INTEL_MID - - help - Say "yes" here to get direct support for the real time clock - found on Moorestown platforms. The VRTC is a emulated RTC that - derives its clock source from a real RTC in the PMIC. The MC146818 - style programming interface is mostly conserved, but any - updates are done via IPC calls to the system controller FW. - config RTC_DRV_DS1216 tristate "Dallas DS1216" depends on SNI_RM diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index bb8f319b09fb..f8ac4f574522 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -174,7 +174,6 @@ obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o -obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c deleted file mode 100644 index 421b3b6071b6..000000000000 --- a/drivers/rtc/rtc-mrst.c +++ /dev/null @@ -1,521 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * rtc-mrst.c: Driver for Moorestown virtual RTC - * - * (C) Copyright 2009 Intel Corporation - * Author: Jacob Pan (jacob.jun.pan@intel.com) - * Feng Tang (feng.tang@intel.com) - * - * Note: - * VRTC is emulated by system controller firmware, the real HW - * RTC is located in the PMIC device. SCU FW shadows PMIC RTC - * in a memory mapped IO space that is visible to the host IA - * processor. - * - * This driver is based upon drivers/rtc/rtc-cmos.c - */ - -/* - * Note: - * * vRTC only supports binary mode and 24H mode - * * vRTC only support PIE and AIE, no UIE, and its PIE only happens - * at 23:59:59pm everyday, no support for adjustable frequency - * * Alarm function is also limited to hr/min/sec. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct mrst_rtc { - struct rtc_device *rtc; - struct device *dev; - int irq; - - u8 enabled_wake; - u8 suspend_ctrl; -}; - -static const char driver_name[] = "rtc_mrst"; - -#define RTC_IRQMASK (RTC_PF | RTC_AF) - -static inline int is_intr(u8 rtc_intr) -{ - if (!(rtc_intr & RTC_IRQF)) - return 0; - return rtc_intr & RTC_IRQMASK; -} - -static inline unsigned char vrtc_is_updating(void) -{ - unsigned char uip; - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - uip = (vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP); - spin_unlock_irqrestore(&rtc_lock, flags); - return uip; -} - -/* - * rtc_time's year contains the increment over 1900, but vRTC's YEAR - * register can't be programmed to value larger than 0x64, so vRTC - * driver chose to use 1972 (1970 is UNIX time start point) as the base, - * and does the translation at read/write time. - * - * Why not just use 1970 as the offset? it's because using 1972 will - * make it consistent in leap year setting for both vrtc and low-level - * physical rtc devices. Then why not use 1960 as the offset? If we use - * 1960, for a device's first use, its YEAR register is 0 and the system - * year will be parsed as 1960 which is not a valid UNIX time and will - * cause many applications to fail mysteriously. - */ -static int mrst_read_time(struct device *dev, struct rtc_time *time) -{ - unsigned long flags; - - if (vrtc_is_updating()) - msleep(20); - - spin_lock_irqsave(&rtc_lock, flags); - time->tm_sec = vrtc_cmos_read(RTC_SECONDS); - time->tm_min = vrtc_cmos_read(RTC_MINUTES); - time->tm_hour = vrtc_cmos_read(RTC_HOURS); - time->tm_mday = vrtc_cmos_read(RTC_DAY_OF_MONTH); - time->tm_mon = vrtc_cmos_read(RTC_MONTH); - time->tm_year = vrtc_cmos_read(RTC_YEAR); - spin_unlock_irqrestore(&rtc_lock, flags); - - /* Adjust for the 1972/1900 */ - time->tm_year += 72; - time->tm_mon--; - return 0; -} - -static int mrst_set_time(struct device *dev, struct rtc_time *time) -{ - int ret; - unsigned long flags; - unsigned char mon, day, hrs, min, sec; - unsigned int yrs; - - yrs = time->tm_year; - mon = time->tm_mon + 1; /* tm_mon starts at zero */ - day = time->tm_mday; - hrs = time->tm_hour; - min = time->tm_min; - sec = time->tm_sec; - - if (yrs < 72 || yrs > 172) - return -EINVAL; - yrs -= 72; - - spin_lock_irqsave(&rtc_lock, flags); - - vrtc_cmos_write(yrs, RTC_YEAR); - vrtc_cmos_write(mon, RTC_MONTH); - vrtc_cmos_write(day, RTC_DAY_OF_MONTH); - vrtc_cmos_write(hrs, RTC_HOURS); - vrtc_cmos_write(min, RTC_MINUTES); - vrtc_cmos_write(sec, RTC_SECONDS); - - spin_unlock_irqrestore(&rtc_lock, flags); - - ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME); - return ret; -} - -static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct mrst_rtc *mrst = dev_get_drvdata(dev); - unsigned char rtc_control; - - if (mrst->irq <= 0) - return -EIO; - - /* vRTC only supports binary mode */ - spin_lock_irq(&rtc_lock); - t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM); - t->time.tm_min = vrtc_cmos_read(RTC_MINUTES_ALARM); - t->time.tm_hour = vrtc_cmos_read(RTC_HOURS_ALARM); - - rtc_control = vrtc_cmos_read(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); - - t->enabled = !!(rtc_control & RTC_AIE); - t->pending = 0; - - return 0; -} - -static void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control) -{ - unsigned char rtc_intr; - - /* - * NOTE after changing RTC_xIE bits we always read INTR_FLAGS; - * allegedly some older rtcs need that to handle irqs properly - */ - rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS); - rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; - if (is_intr(rtc_intr)) - rtc_update_irq(mrst->rtc, 1, rtc_intr); -} - -static void mrst_irq_enable(struct mrst_rtc *mrst, unsigned char mask) -{ - unsigned char rtc_control; - - /* - * Flush any pending IRQ status, notably for update irqs, - * before we enable new IRQs - */ - rtc_control = vrtc_cmos_read(RTC_CONTROL); - mrst_checkintr(mrst, rtc_control); - - rtc_control |= mask; - vrtc_cmos_write(rtc_control, RTC_CONTROL); - - mrst_checkintr(mrst, rtc_control); -} - -static void mrst_irq_disable(struct mrst_rtc *mrst, unsigned char mask) -{ - unsigned char rtc_control; - - rtc_control = vrtc_cmos_read(RTC_CONTROL); - rtc_control &= ~mask; - vrtc_cmos_write(rtc_control, RTC_CONTROL); - mrst_checkintr(mrst, rtc_control); -} - -static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct mrst_rtc *mrst = dev_get_drvdata(dev); - unsigned char hrs, min, sec; - int ret = 0; - - if (!mrst->irq) - return -EIO; - - hrs = t->time.tm_hour; - min = t->time.tm_min; - sec = t->time.tm_sec; - - spin_lock_irq(&rtc_lock); - /* Next rtc irq must not be from previous alarm setting */ - mrst_irq_disable(mrst, RTC_AIE); - - /* Update alarm */ - vrtc_cmos_write(hrs, RTC_HOURS_ALARM); - vrtc_cmos_write(min, RTC_MINUTES_ALARM); - vrtc_cmos_write(sec, RTC_SECONDS_ALARM); - - spin_unlock_irq(&rtc_lock); - - ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM); - if (ret) - return ret; - - spin_lock_irq(&rtc_lock); - if (t->enabled) - mrst_irq_enable(mrst, RTC_AIE); - - spin_unlock_irq(&rtc_lock); - - return 0; -} - -/* Currently, the vRTC doesn't support UIE ON/OFF */ -static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct mrst_rtc *mrst = dev_get_drvdata(dev); - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - if (enabled) - mrst_irq_enable(mrst, RTC_AIE); - else - mrst_irq_disable(mrst, RTC_AIE); - spin_unlock_irqrestore(&rtc_lock, flags); - return 0; -} - - -#if IS_ENABLED(CONFIG_RTC_INTF_PROC) - -static int mrst_procfs(struct device *dev, struct seq_file *seq) -{ - unsigned char rtc_control; - - spin_lock_irq(&rtc_lock); - rtc_control = vrtc_cmos_read(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); - - seq_printf(seq, - "periodic_IRQ\t: %s\n" - "alarm\t\t: %s\n" - "BCD\t\t: no\n" - "periodic_freq\t: daily (not adjustable)\n", - (rtc_control & RTC_PIE) ? "on" : "off", - (rtc_control & RTC_AIE) ? "on" : "off"); - - return 0; -} - -#else -#define mrst_procfs NULL -#endif - -static const struct rtc_class_ops mrst_rtc_ops = { - .read_time = mrst_read_time, - .set_time = mrst_set_time, - .read_alarm = mrst_read_alarm, - .set_alarm = mrst_set_alarm, - .proc = mrst_procfs, - .alarm_irq_enable = mrst_rtc_alarm_irq_enable, -}; - -static struct mrst_rtc mrst_rtc; - -/* - * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in - * Reg B, so no need for this driver to clear it - */ -static irqreturn_t mrst_rtc_irq(int irq, void *p) -{ - u8 irqstat; - - spin_lock(&rtc_lock); - /* This read will clear all IRQ flags inside Reg C */ - irqstat = vrtc_cmos_read(RTC_INTR_FLAGS); - spin_unlock(&rtc_lock); - - irqstat &= RTC_IRQMASK | RTC_IRQF; - if (is_intr(irqstat)) { - rtc_update_irq(p, 1, irqstat); - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, - int rtc_irq) -{ - int retval = 0; - unsigned char rtc_control; - - /* There can be only one ... */ - if (mrst_rtc.dev) - return -EBUSY; - - if (!iomem) - return -ENODEV; - - iomem = devm_request_mem_region(dev, iomem->start, resource_size(iomem), - driver_name); - if (!iomem) { - dev_dbg(dev, "i/o mem already in use.\n"); - return -EBUSY; - } - - mrst_rtc.irq = rtc_irq; - mrst_rtc.dev = dev; - dev_set_drvdata(dev, &mrst_rtc); - - mrst_rtc.rtc = devm_rtc_allocate_device(dev); - if (IS_ERR(mrst_rtc.rtc)) - return PTR_ERR(mrst_rtc.rtc); - - mrst_rtc.rtc->ops = &mrst_rtc_ops; - - rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); - - spin_lock_irq(&rtc_lock); - mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE); - rtc_control = vrtc_cmos_read(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); - - if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) - dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n"); - - if (rtc_irq) { - retval = devm_request_irq(dev, rtc_irq, mrst_rtc_irq, - 0, dev_name(&mrst_rtc.rtc->dev), - mrst_rtc.rtc); - if (retval < 0) { - dev_dbg(dev, "IRQ %d is already in use, err %d\n", - rtc_irq, retval); - goto cleanup0; - } - } - - retval = devm_rtc_register_device(mrst_rtc.rtc); - if (retval) - goto cleanup0; - - dev_dbg(dev, "initialised\n"); - return 0; - -cleanup0: - mrst_rtc.dev = NULL; - dev_err(dev, "rtc-mrst: unable to initialise\n"); - return retval; -} - -static void rtc_mrst_do_shutdown(void) -{ - spin_lock_irq(&rtc_lock); - mrst_irq_disable(&mrst_rtc, RTC_IRQMASK); - spin_unlock_irq(&rtc_lock); -} - -static void rtc_mrst_do_remove(struct device *dev) -{ - struct mrst_rtc *mrst = dev_get_drvdata(dev); - - rtc_mrst_do_shutdown(); - - mrst->rtc = NULL; - mrst->dev = NULL; -} - -#ifdef CONFIG_PM_SLEEP -static int mrst_suspend(struct device *dev) -{ - struct mrst_rtc *mrst = dev_get_drvdata(dev); - unsigned char tmp; - - /* Only the alarm might be a wakeup event source */ - spin_lock_irq(&rtc_lock); - mrst->suspend_ctrl = tmp = vrtc_cmos_read(RTC_CONTROL); - if (tmp & (RTC_PIE | RTC_AIE)) { - unsigned char mask; - - if (device_may_wakeup(dev)) - mask = RTC_IRQMASK & ~RTC_AIE; - else - mask = RTC_IRQMASK; - tmp &= ~mask; - vrtc_cmos_write(tmp, RTC_CONTROL); - - mrst_checkintr(mrst, tmp); - } - spin_unlock_irq(&rtc_lock); - - if (tmp & RTC_AIE) { - mrst->enabled_wake = 1; - enable_irq_wake(mrst->irq); - } - - dev_dbg(&mrst_rtc.rtc->dev, "suspend%s, ctrl %02x\n", - (tmp & RTC_AIE) ? ", alarm may wake" : "", - tmp); - - return 0; -} - -/* - * We want RTC alarms to wake us from the deep power saving state - */ -static inline int mrst_poweroff(struct device *dev) -{ - return mrst_suspend(dev); -} - -static int mrst_resume(struct device *dev) -{ - struct mrst_rtc *mrst = dev_get_drvdata(dev); - unsigned char tmp = mrst->suspend_ctrl; - - /* Re-enable any irqs previously active */ - if (tmp & RTC_IRQMASK) { - unsigned char mask; - - if (mrst->enabled_wake) { - disable_irq_wake(mrst->irq); - mrst->enabled_wake = 0; - } - - spin_lock_irq(&rtc_lock); - do { - vrtc_cmos_write(tmp, RTC_CONTROL); - - mask = vrtc_cmos_read(RTC_INTR_FLAGS); - mask &= (tmp & RTC_IRQMASK) | RTC_IRQF; - if (!is_intr(mask)) - break; - - rtc_update_irq(mrst->rtc, 1, mask); - tmp &= ~RTC_AIE; - } while (mask & RTC_AIE); - spin_unlock_irq(&rtc_lock); - } - - dev_dbg(&mrst_rtc.rtc->dev, "resume, ctrl %02x\n", tmp); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume); -#define MRST_PM_OPS (&mrst_pm_ops) - -#else -#define MRST_PM_OPS NULL - -static inline int mrst_poweroff(struct device *dev) -{ - return -ENOSYS; -} - -#endif - -static int vrtc_mrst_platform_probe(struct platform_device *pdev) -{ - return vrtc_mrst_do_probe(&pdev->dev, - platform_get_resource(pdev, IORESOURCE_MEM, 0), - platform_get_irq(pdev, 0)); -} - -static int vrtc_mrst_platform_remove(struct platform_device *pdev) -{ - rtc_mrst_do_remove(&pdev->dev); - return 0; -} - -static void vrtc_mrst_platform_shutdown(struct platform_device *pdev) -{ - if (system_state == SYSTEM_POWER_OFF && !mrst_poweroff(&pdev->dev)) - return; - - rtc_mrst_do_shutdown(); -} - -MODULE_ALIAS("platform:vrtc_mrst"); - -static struct platform_driver vrtc_mrst_platform_driver = { - .probe = vrtc_mrst_platform_probe, - .remove = vrtc_mrst_platform_remove, - .shutdown = vrtc_mrst_platform_shutdown, - .driver = { - .name = driver_name, - .pm = MRST_PM_OPS, - } -}; - -module_platform_driver(vrtc_mrst_platform_driver); - -MODULE_AUTHOR("Jacob Pan; Feng Tang"); -MODULE_DESCRIPTION("Driver for Moorestown virtual RTC"); -MODULE_LICENSE("GPL"); From 1b5b5b4eb52216af05ae4eebbe2efebed4f15a1c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Nov 2019 16:57:30 +0200 Subject: [PATCH 08/12] watchdog: intel_scu_watchdog: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Acked-by: Linus Walleij --- drivers/watchdog/Kconfig | 9 - drivers/watchdog/Makefile | 1 - drivers/watchdog/intel_scu_watchdog.c | 533 -------------------------- drivers/watchdog/intel_scu_watchdog.h | 50 --- 4 files changed, 593 deletions(-) delete mode 100644 drivers/watchdog/intel_scu_watchdog.c delete mode 100644 drivers/watchdog/intel_scu_watchdog.h diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 7ff941e71b79..6b9e93d8532b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1219,15 +1219,6 @@ config IE6XX_WDT To compile this driver as a module, choose M here: the module will be called ie6xx_wdt. -config INTEL_SCU_WATCHDOG - bool "Intel SCU Watchdog for Mobile Platforms" - depends on X86_INTEL_MID - help - Hardware driver for the watchdog time built into the Intel SCU - for Intel Mobile Platforms. - - To compile this driver as a module, choose M here. - config INTEL_MID_WATCHDOG tristate "Intel MID Watchdog Timer" depends on X86_INTEL_MID diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5c74ee19d441..74f61e4105d8 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -140,7 +140,6 @@ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o -obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c deleted file mode 100644 index 804e35940983..000000000000 --- a/drivers/watchdog/intel_scu_watchdog.c +++ /dev/null @@ -1,533 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device - * for Intel part #(s): - * - AF82MP20 PCH - * - * Copyright (C) 2009-2010 Intel Corporation. All rights reserved. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intel_scu_watchdog.h" - -/* Bounds number of times we will retry loading time count */ -/* This retry is a work around for a silicon bug. */ -#define MAX_RETRY 16 - -#define IPC_SET_WATCHDOG_TIMER 0xF8 - -static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN; -module_param(timer_margin, int, 0); -MODULE_PARM_DESC(timer_margin, - "Watchdog timer margin" - "Time between interrupt and resetting the system" - "The range is from 1 to 160" - "This is the time for all keep alives to arrive"); - -static int timer_set = DEFAULT_TIME; -module_param(timer_set, int, 0); -MODULE_PARM_DESC(timer_set, - "Default Watchdog timer setting" - "Complete cycle time" - "The range is from 1 to 170" - "This is the time for all keep alives to arrive"); - -/* After watchdog device is closed, check force_boot. If: - * force_boot == 0, then force boot on next watchdog interrupt after close, - * force_boot == 1, then force boot immediately when device is closed. - */ -static int force_boot; -module_param(force_boot, int, 0); -MODULE_PARM_DESC(force_boot, - "A value of 1 means that the driver will reboot" - "the system immediately if the /dev/watchdog device is closed" - "A value of 0 means that when /dev/watchdog device is closed" - "the watchdog timer will be refreshed for one more interval" - "of length: timer_set. At the end of this interval, the" - "watchdog timer will reset the system." - ); - -/* there is only one device in the system now; this can be made into - * an array in the future if we have more than one device */ - -static struct intel_scu_watchdog_dev watchdog_device; - -/* Forces restart, if force_reboot is set */ -static void watchdog_fire(void) -{ - if (force_boot) { - pr_crit("Initiating system reboot\n"); - emergency_restart(); - pr_crit("Reboot didn't ?????\n"); - } - - else { - pr_crit("Immediate Reboot Disabled\n"); - pr_crit("System will reset when watchdog timer times out!\n"); - } -} - -static int check_timer_margin(int new_margin) -{ - if ((new_margin < MIN_TIME_CYCLE) || - (new_margin > MAX_TIME - timer_set)) { - pr_debug("value of new_margin %d is out of the range %d to %d\n", - new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set); - return -EINVAL; - } - return 0; -} - -/* - * IPC operations - */ -static int watchdog_set_ipc(int soft_threshold, int threshold) -{ - u32 *ipc_wbuf; - u8 cbuf[16] = { '\0' }; - int ipc_ret = 0; - - ipc_wbuf = (u32 *)&cbuf; - ipc_wbuf[0] = soft_threshold; - ipc_wbuf[1] = threshold; - - ipc_ret = intel_scu_ipc_command( - IPC_SET_WATCHDOG_TIMER, - 0, - ipc_wbuf, - 2, - NULL, - 0); - - if (ipc_ret != 0) - pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret); - - return ipc_ret; -}; - -/* - * Intel_SCU operations - */ - -/* timer interrupt handler */ -static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id) -{ - int int_status; - int_status = ioread32(watchdog_device.timer_interrupt_status_addr); - - pr_debug("irq, int_status: %x\n", int_status); - - if (int_status != 0) - return IRQ_NONE; - - /* has the timer been started? If not, then this is spurious */ - if (watchdog_device.timer_started == 0) { - pr_debug("spurious interrupt received\n"); - return IRQ_HANDLED; - } - - /* temporarily disable the timer */ - iowrite32(0x00000002, watchdog_device.timer_control_addr); - - /* set the timer to the threshold */ - iowrite32(watchdog_device.threshold, - watchdog_device.timer_load_count_addr); - - /* allow the timer to run */ - iowrite32(0x00000003, watchdog_device.timer_control_addr); - - return IRQ_HANDLED; -} - -static int intel_scu_keepalive(void) -{ - - /* read eoi register - clears interrupt */ - ioread32(watchdog_device.timer_clear_interrupt_addr); - - /* temporarily disable the timer */ - iowrite32(0x00000002, watchdog_device.timer_control_addr); - - /* set the timer to the soft_threshold */ - iowrite32(watchdog_device.soft_threshold, - watchdog_device.timer_load_count_addr); - - /* allow the timer to run */ - iowrite32(0x00000003, watchdog_device.timer_control_addr); - - return 0; -} - -static int intel_scu_stop(void) -{ - iowrite32(0, watchdog_device.timer_control_addr); - return 0; -} - -static int intel_scu_set_heartbeat(u32 t) -{ - int ipc_ret; - int retry_count; - u32 soft_value; - u32 hw_value; - - watchdog_device.timer_set = t; - watchdog_device.threshold = - timer_margin * watchdog_device.timer_tbl_ptr->freq_hz; - watchdog_device.soft_threshold = - (watchdog_device.timer_set - timer_margin) - * watchdog_device.timer_tbl_ptr->freq_hz; - - pr_debug("set_heartbeat: timer freq is %d\n", - watchdog_device.timer_tbl_ptr->freq_hz); - pr_debug("set_heartbeat: timer_set is %x (hex)\n", - watchdog_device.timer_set); - pr_debug("set_heartbeat: timer_margin is %x (hex)\n", timer_margin); - pr_debug("set_heartbeat: threshold is %x (hex)\n", - watchdog_device.threshold); - pr_debug("set_heartbeat: soft_threshold is %x (hex)\n", - watchdog_device.soft_threshold); - - /* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */ - /* watchdog timing come out right. */ - watchdog_device.threshold = - watchdog_device.threshold / FREQ_ADJUSTMENT; - watchdog_device.soft_threshold = - watchdog_device.soft_threshold / FREQ_ADJUSTMENT; - - /* temporarily disable the timer */ - iowrite32(0x00000002, watchdog_device.timer_control_addr); - - /* send the threshold and soft_threshold via IPC to the processor */ - ipc_ret = watchdog_set_ipc(watchdog_device.soft_threshold, - watchdog_device.threshold); - - if (ipc_ret != 0) { - /* Make sure the watchdog timer is stopped */ - intel_scu_stop(); - return ipc_ret; - } - - /* Soft Threshold set loop. Early versions of silicon did */ - /* not always set this count correctly. This loop checks */ - /* the value and retries if it was not set correctly. */ - - retry_count = 0; - soft_value = watchdog_device.soft_threshold & 0xFFFF0000; - do { - - /* Make sure timer is stopped */ - intel_scu_stop(); - - if (MAX_RETRY < retry_count++) { - /* Unable to set timer value */ - pr_err("Unable to set timer\n"); - return -ENODEV; - } - - /* set the timer to the soft threshold */ - iowrite32(watchdog_device.soft_threshold, - watchdog_device.timer_load_count_addr); - - /* read count value before starting timer */ - ioread32(watchdog_device.timer_load_count_addr); - - /* Start the timer */ - iowrite32(0x00000003, watchdog_device.timer_control_addr); - - /* read the value the time loaded into its count reg */ - hw_value = ioread32(watchdog_device.timer_load_count_addr); - hw_value = hw_value & 0xFFFF0000; - - - } while (soft_value != hw_value); - - watchdog_device.timer_started = 1; - - return 0; -} - -/* - * /dev/watchdog handling - */ - -static int intel_scu_open(struct inode *inode, struct file *file) -{ - - /* Set flag to indicate that watchdog device is open */ - if (test_and_set_bit(0, &watchdog_device.driver_open)) - return -EBUSY; - - /* Check for reopen of driver. Reopens are not allowed */ - if (watchdog_device.driver_closed) - return -EPERM; - - return stream_open(inode, file); -} - -static int intel_scu_release(struct inode *inode, struct file *file) -{ - /* - * This watchdog should not be closed, after the timer - * is started with the WDIPC_SETTIMEOUT ioctl - * If force_boot is set watchdog_fire() will cause an - * immediate reset. If force_boot is not set, the watchdog - * timer is refreshed for one more interval. At the end - * of that interval, the watchdog timer will reset the system. - */ - - if (!test_and_clear_bit(0, &watchdog_device.driver_open)) { - pr_debug("intel_scu_release, without open\n"); - return -ENOTTY; - } - - if (!watchdog_device.timer_started) { - /* Just close, since timer has not been started */ - pr_debug("closed, without starting timer\n"); - return 0; - } - - pr_crit("Unexpected close of /dev/watchdog!\n"); - - /* Since the timer was started, prevent future reopens */ - watchdog_device.driver_closed = 1; - - /* Refresh the timer for one more interval */ - intel_scu_keepalive(); - - /* Reboot system (if force_boot is set) */ - watchdog_fire(); - - /* We should only reach this point if force_boot is not set */ - return 0; -} - -static ssize_t intel_scu_write(struct file *file, - char const *data, - size_t len, - loff_t *ppos) -{ - - if (watchdog_device.timer_started) - /* Watchdog already started, keep it alive */ - intel_scu_keepalive(); - else - /* Start watchdog with timer value set by init */ - intel_scu_set_heartbeat(watchdog_device.timer_set); - - return len; -} - -static long intel_scu_ioctl(struct file *file, - unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - u32 __user *p = argp; - u32 new_margin; - - - static const struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT - | WDIOF_KEEPALIVEPING, - .firmware_version = 0, /* @todo Get from SCU via - ipc_get_scu_fw_version()? */ - .identity = "Intel_SCU IOH Watchdog" /* len < 32 */ - }; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, - &ident, - sizeof(ident)) ? -EFAULT : 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_KEEPALIVE: - intel_scu_keepalive(); - - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_margin, p)) - return -EFAULT; - - if (check_timer_margin(new_margin)) - return -EINVAL; - - if (intel_scu_set_heartbeat(new_margin)) - return -EINVAL; - return 0; - case WDIOC_GETTIMEOUT: - return put_user(watchdog_device.soft_threshold, p); - - default: - return -ENOTTY; - } -} - -/* - * Notifier for system down - */ -static int intel_scu_notify_sys(struct notifier_block *this, - unsigned long code, - void *another_unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - /* Turn off the watchdog timer. */ - intel_scu_stop(); - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ -static const struct file_operations intel_scu_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = intel_scu_write, - .unlocked_ioctl = intel_scu_ioctl, - .compat_ioctl = compat_ptr_ioctl, - .open = intel_scu_open, - .release = intel_scu_release, -}; - -static int __init intel_scu_watchdog_init(void) -{ - int ret; - u32 __iomem *tmp_addr; - - /* - * We don't really need to check this as the SFI timer get will fail - * but if we do so we can exit with a clearer reason and no noise. - * - * If it isn't an intel MID device then it doesn't have this watchdog - */ - if (!intel_mid_identify_cpu()) - return -ENODEV; - - /* Check boot parameters to verify that their initial values */ - /* are in range. */ - /* Check value of timer_set boot parameter */ - if ((timer_set < MIN_TIME_CYCLE) || - (timer_set > MAX_TIME - MIN_TIME_CYCLE)) { - pr_err("value of timer_set %x (hex) is out of range from %x to %x (hex)\n", - timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE); - return -EINVAL; - } - - /* Check value of timer_margin boot parameter */ - if (check_timer_margin(timer_margin)) - return -EINVAL; - - watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1); - - if (watchdog_device.timer_tbl_ptr == NULL) { - pr_debug("timer is not available\n"); - return -ENODEV; - } - /* make sure the timer exists */ - if (watchdog_device.timer_tbl_ptr->phys_addr == 0) { - pr_debug("timer %d does not have valid physical memory\n", - sfi_mtimer_num); - return -ENODEV; - } - - if (watchdog_device.timer_tbl_ptr->irq == 0) { - pr_debug("timer %d invalid irq\n", sfi_mtimer_num); - return -ENODEV; - } - - tmp_addr = ioremap(watchdog_device.timer_tbl_ptr->phys_addr, - 20); - - if (tmp_addr == NULL) { - pr_debug("timer unable to ioremap\n"); - return -ENOMEM; - } - - watchdog_device.timer_load_count_addr = tmp_addr++; - watchdog_device.timer_current_value_addr = tmp_addr++; - watchdog_device.timer_control_addr = tmp_addr++; - watchdog_device.timer_clear_interrupt_addr = tmp_addr++; - watchdog_device.timer_interrupt_status_addr = tmp_addr++; - - /* Set the default time values in device structure */ - - watchdog_device.timer_set = timer_set; - watchdog_device.threshold = - timer_margin * watchdog_device.timer_tbl_ptr->freq_hz; - watchdog_device.soft_threshold = - (watchdog_device.timer_set - timer_margin) - * watchdog_device.timer_tbl_ptr->freq_hz; - - - watchdog_device.intel_scu_notifier.notifier_call = - intel_scu_notify_sys; - - ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier); - if (ret) { - pr_err("cannot register notifier %d)\n", ret); - goto register_reboot_error; - } - - watchdog_device.miscdev.minor = WATCHDOG_MINOR; - watchdog_device.miscdev.name = "watchdog"; - watchdog_device.miscdev.fops = &intel_scu_fops; - - ret = misc_register(&watchdog_device.miscdev); - if (ret) { - pr_err("cannot register miscdev %d err =%d\n", - WATCHDOG_MINOR, ret); - goto misc_register_error; - } - - ret = request_irq((unsigned int)watchdog_device.timer_tbl_ptr->irq, - watchdog_timer_interrupt, - IRQF_SHARED, "watchdog", - &watchdog_device.timer_load_count_addr); - if (ret) { - pr_err("error requesting irq %d\n", ret); - goto request_irq_error; - } - /* Make sure timer is disabled before returning */ - intel_scu_stop(); - return 0; - -/* error cleanup */ - -request_irq_error: - misc_deregister(&watchdog_device.miscdev); -misc_register_error: - unregister_reboot_notifier(&watchdog_device.intel_scu_notifier); -register_reboot_error: - intel_scu_stop(); - iounmap(watchdog_device.timer_load_count_addr); - return ret; -} -late_initcall(intel_scu_watchdog_init); diff --git a/drivers/watchdog/intel_scu_watchdog.h b/drivers/watchdog/intel_scu_watchdog.h deleted file mode 100644 index fb12a25ee417..000000000000 --- a/drivers/watchdog/intel_scu_watchdog.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device - * for Intel part #(s): - * - AF82MP20 PCH - * - * Copyright (C) 2009-2010 Intel Corporation. All rights reserved. - */ - -#ifndef __INTEL_SCU_WATCHDOG_H -#define __INTEL_SCU_WATCHDOG_H - -#define WDT_VER "0.3" - -/* minimum time between interrupts */ -#define MIN_TIME_CYCLE 1 - -/* Time from warning to reboot is 2 seconds */ -#define DEFAULT_SOFT_TO_HARD_MARGIN 2 - -#define MAX_TIME 170 - -#define DEFAULT_TIME 5 - -#define MAX_SOFT_TO_HARD_MARGIN (MAX_TIME-MIN_TIME_CYCLE) - -/* Ajustment to clock tick frequency to make timing come out right */ -#define FREQ_ADJUSTMENT 8 - -struct intel_scu_watchdog_dev { - ulong driver_open; - ulong driver_closed; - u32 timer_started; - u32 timer_set; - u32 threshold; - u32 soft_threshold; - u32 __iomem *timer_load_count_addr; - u32 __iomem *timer_current_value_addr; - u32 __iomem *timer_control_addr; - u32 __iomem *timer_clear_interrupt_addr; - u32 __iomem *timer_interrupt_status_addr; - struct sfi_timer_table_entry *timer_tbl_ptr; - struct notifier_block intel_scu_notifier; - struct miscdevice miscdev; -}; - -extern int sfi_mtimer_num; - -/* extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); */ -#endif /* __INTEL_SCU_WATCHDOG_H */ From f285c9532b5bd3de7e37a6203318437cab79bd9a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Oct 2020 19:33:02 +0300 Subject: [PATCH 09/12] watchdog: intel-mid_wdt: Postpone IRQ handler registration till SCU is ready When SCU is not ready and CONFIG_DEBUG_SHIRQ=y we got deferred probe followed by fired test IRQ which immediately makes kernel panic. Fix this by delaying IRQ handler registration till SCU is ready. Fixes: 80ae679b8f86 ("watchdog: intel-mid_wdt: Convert to use new SCU IPC API") Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Acked-by: Linus Walleij Reviewed-by: Mika Westerberg --- drivers/watchdog/intel-mid_wdt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index 1ae03b64ef8b..9b2173f765c8 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -154,6 +154,10 @@ static int mid_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(wdt_dev, WATCHDOG_NOWAYOUT); watchdog_set_drvdata(wdt_dev, mid); + mid->scu = devm_intel_scu_ipc_dev_get(dev); + if (!mid->scu) + return -EPROBE_DEFER; + ret = devm_request_irq(dev, pdata->irq, mid_wdt_irq, IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog", wdt_dev); @@ -162,10 +166,6 @@ static int mid_wdt_probe(struct platform_device *pdev) return ret; } - mid->scu = devm_intel_scu_ipc_dev_get(dev); - if (!mid->scu) - return -EPROBE_DEFER; - /* * The firmware followed by U-Boot leaves the watchdog running * with the default threshold which may vary. When we get here From 18365d686e1ee953983e04b7beca4362bff56297 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Oct 2020 19:03:19 +0300 Subject: [PATCH 10/12] platform/x86: intel_scu_wdt: Move driver from arch/x86 The ACPI-enabled Intel MID platforms neither have WDAT table nor proper IDs to instantiate watchdog device. In order to keep them working move the board code from arch/x86 to drivers/platform/x86. Note, the complete SFI support is going to be removed, that's why PDx86 has been chosen as a new home for it. This is the only device which needs additional code so far. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Reviewed-by: Hans de Goede Acked-by: Linus Walleij --- arch/x86/platform/intel-mid/device_libs/Makefile | 1 - drivers/platform/x86/Kconfig | 8 ++++++++ drivers/platform/x86/Makefile | 1 + .../platform/x86/intel_scu_wdt.c | 0 4 files changed, 9 insertions(+), 1 deletion(-) rename arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c => drivers/platform/x86/intel_scu_wdt.c (100%) diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile index 480fed21cc7d..918edac9ab9a 100644 --- a/arch/x86/platform/intel-mid/device_libs/Makefile +++ b/arch/x86/platform/intel-mid/device_libs/Makefile @@ -30,4 +30,3 @@ obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_tca6416.o obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o obj-$(subst m,y,$(CONFIG_INTEL_MID_POWER_BUTTON)) += platform_mrfld_power_btn.o obj-$(subst m,y,$(CONFIG_RTC_DRV_CMOS)) += platform_mrfld_rtc.o -obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_mrfld_wdt.o diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 4a5798a0ce0c..0bb85eabace1 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1424,6 +1424,14 @@ config INTEL_SCU_PLATFORM and SCU (sometimes called PMC as well). The driver currently supports Intel Elkhart Lake and compatible platforms. +config INTEL_SCU_WDT + bool + default INTEL_SCU_PCI + depends on INTEL_MID_WATCHDOG + help + This is a specific platform code to instantiate watchdog device + on ACPI-based Intel MID platforms. + config INTEL_SCU_IPC_UTIL tristate "Intel SCU IPC utility driver" depends on INTEL_SCU diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 728ccc226a29..19306450d791 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -146,6 +146,7 @@ obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o obj-$(CONFIG_INTEL_SCU_PLATFORM) += intel_scu_pltdrv.o +obj-$(CONFIG_INTEL_SCU_WDT) += intel_scu_wdt.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c b/drivers/platform/x86/intel_scu_wdt.c similarity index 100% rename from arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c rename to drivers/platform/x86/intel_scu_wdt.c From 55627c70db6ad41371ed07a64c6e58d258ab0ae9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Oct 2020 19:14:15 +0300 Subject: [PATCH 11/12] platform/x86: intel_scu_wdt: Drop SCU notification Since SCU code along with the Intel MID watchdog driver has been refactored in a way that latter will be probed only after the former has been come to live, the notification code is bogus and not needed. Remove it for good. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Reviewed-by: Hans de Goede Acked-by: Linus Walleij --- drivers/platform/x86/intel_scu_wdt.c | 31 +++++++--------------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/platform/x86/intel_scu_wdt.c b/drivers/platform/x86/intel_scu_wdt.c index 227218a8f98e..19f7686a3c19 100644 --- a/drivers/platform/x86/intel_scu_wdt.c +++ b/drivers/platform/x86/intel_scu_wdt.c @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -49,34 +48,18 @@ static struct intel_mid_wdt_pdata tangier_pdata = { .probe = tangier_probe, }; -static int wdt_scu_status_change(struct notifier_block *nb, - unsigned long code, void *data) -{ - if (code == SCU_DOWN) { - platform_device_unregister(&wdt_dev); - return 0; - } - - return platform_device_register(&wdt_dev); -} - -static struct notifier_block wdt_scu_notifier = { - .notifier_call = wdt_scu_status_change, -}; - static int __init register_mid_wdt(void) { if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER) return -ENODEV; wdt_dev.dev.platform_data = &tangier_pdata; - - /* - * We need to be sure that the SCU IPC is ready before watchdog device - * can be registered: - */ - intel_scu_notifier_add(&wdt_scu_notifier); - - return 0; + return platform_device_register(&wdt_dev); } arch_initcall(register_mid_wdt); + +static void __exit unregister_mid_wdt(void) +{ + platform_device_unregister(&wdt_dev); +} +__exitcall(unregister_mid_wdt); From a507e5d90f3d6846a02d9c2c79e6f6395982db92 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jul 2018 20:45:36 +0300 Subject: [PATCH 12/12] platform/x86: intel_scu_wdt: Get rid of custom x86 model comparison Switch the platform code to use x86_id_table and accompanying API instead of custom comparison against x86 CPU model. This is one of the last users of custom API for that and following changes will remove it for the good. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck --- drivers/platform/x86/intel_scu_wdt.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel_scu_wdt.c b/drivers/platform/x86/intel_scu_wdt.c index 19f7686a3c19..85ee85ca2215 100644 --- a/drivers/platform/x86/intel_scu_wdt.c +++ b/drivers/platform/x86/intel_scu_wdt.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -48,12 +50,20 @@ static struct intel_mid_wdt_pdata tangier_pdata = { .probe = tangier_probe, }; +static const struct x86_cpu_id intel_mid_cpu_ids[] = { + X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &tangier_pdata), + {} +}; + static int __init register_mid_wdt(void) { - if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER) + const struct x86_cpu_id *id; + + id = x86_match_cpu(intel_mid_cpu_ids); + if (!id) return -ENODEV; - wdt_dev.dev.platform_data = &tangier_pdata; + wdt_dev.dev.platform_data = (const struct intel_mid_wdt_pdata *)id->driver_data; return platform_device_register(&wdt_dev); } arch_initcall(register_mid_wdt);