From 297b60346df8beafee954a0fd7c2d64f33f3b9bc Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 11 May 2024 01:44:05 +0000 Subject: [PATCH] rtl8211F_led_control --- kernel/drivers/gpio/gpio-vf610.c | 117 ++++++++++++++++++++++++++++++++++++---------------------- 1 files changed, 73 insertions(+), 44 deletions(-) diff --git a/kernel/drivers/gpio/gpio-vf610.c b/kernel/drivers/gpio/gpio-vf610.c index a9cb557..396a687 100644 --- a/kernel/drivers/gpio/gpio-vf610.c +++ b/kernel/drivers/gpio/gpio-vf610.c @@ -1,23 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale vf610 GPIO support through PORT and GPIO * * Copyright (c) 2014 Toradex AG. * * Author: Stefan Agner <stefan@agner.ch>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ - #include <linux/bitops.h> +#include <linux/clk.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -42,6 +34,8 @@ void __iomem *gpio_base; const struct fsl_gpio_soc_data *sdata; u8 irqc[VF610_GPIO_PER_PORT]; + struct clk *clk_port; + struct clk *clk_gpio; int irq; }; @@ -91,28 +85,24 @@ { struct vf610_gpio_port *port = gpiochip_get_data(gc); unsigned long mask = BIT(gpio); - void __iomem *addr; + unsigned long offset = GPIO_PDIR; if (port->sdata && port->sdata->have_paddr) { mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR); - addr = mask ? port->gpio_base + GPIO_PDOR : - port->gpio_base + GPIO_PDIR; - return !!(vf610_gpio_readl(addr) & BIT(gpio)); - } else { - return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) - & BIT(gpio)); + if (mask) + offset = GPIO_PDOR; } + + return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio)); } static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct vf610_gpio_port *port = gpiochip_get_data(gc); unsigned long mask = BIT(gpio); + unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR; - if (val) - vf610_gpio_writel(mask, port->gpio_base + GPIO_PSOR); - else - vf610_gpio_writel(mask, port->gpio_base + GPIO_PCOR); + vf610_gpio_writel(mask, port->gpio_base + offset); } static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) @@ -135,9 +125,13 @@ { struct vf610_gpio_port *port = gpiochip_get_data(chip); unsigned long mask = BIT(gpio); + u32 val; - if (port->sdata && port->sdata->have_paddr) - vf610_gpio_writel(mask, port->gpio_base + GPIO_PDDR); + if (port->sdata && port->sdata->have_paddr) { + val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR); + val |= mask; + vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR); + } vf610_gpio_set(chip, gpio, value); @@ -242,29 +236,32 @@ return 0; } +static void vf610_gpio_disable_clk(void *data) +{ + clk_disable_unprepare(data); +} + static int vf610_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct vf610_gpio_port *port; - struct resource *iores; struct gpio_chip *gc; + struct gpio_irq_chip *girq; struct irq_chip *ic; int i; int ret; - port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; port->sdata = of_device_get_match_data(dev); - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - port->base = devm_ioremap_resource(dev, iores); + port->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(port->base)) return PTR_ERR(port->base); - iores = platform_get_resource(pdev, IORESOURCE_MEM, 1); - port->gpio_base = devm_ioremap_resource(dev, iores); + port->gpio_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(port->gpio_base)) return PTR_ERR(port->gpio_base); @@ -272,10 +269,42 @@ if (port->irq < 0) return port->irq; + port->clk_port = devm_clk_get(dev, "port"); + ret = PTR_ERR_OR_ZERO(port->clk_port); + if (!ret) { + ret = clk_prepare_enable(port->clk_port); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk, + port->clk_port); + if (ret) + return ret; + } else if (ret == -EPROBE_DEFER) { + /* + * Percolate deferrals, for anything else, + * just live without the clocking. + */ + return ret; + } + + port->clk_gpio = devm_clk_get(dev, "gpio"); + ret = PTR_ERR_OR_ZERO(port->clk_gpio); + if (!ret) { + ret = clk_prepare_enable(port->clk_gpio); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk, + port->clk_gpio); + if (ret) + return ret; + } else if (ret == -EPROBE_DEFER) { + return ret; + } + gc = &port->gc; gc->of_node = np; gc->parent = dev; - gc->label = "vf610-gpio"; + gc->label = dev_name(dev); gc->ngpio = VF610_GPIO_PER_PORT; gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT; @@ -294,10 +323,6 @@ ic->irq_set_type = vf610_gpio_irq_set_type; ic->irq_set_wake = vf610_gpio_irq_set_wake; - ret = gpiochip_add_data(gc, port); - if (ret < 0) - return ret; - /* Mask all GPIO interrupts */ for (i = 0; i < gc->ngpio; i++) vf610_gpio_writel(0, port->base + PORT_PCR(i)); @@ -305,16 +330,20 @@ /* Clear the interrupt status register for all GPIO's */ vf610_gpio_writel(~0, port->base + PORT_ISFR); - ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "failed to add irqchip\n"); - gpiochip_remove(gc); - return ret; - } - gpiochip_set_chained_irqchip(gc, ic, port->irq, - vf610_gpio_irq_handler); + girq = &gc->irq; + girq->chip = ic; + girq->parent_handler = vf610_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = port->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_edge_irq; - return 0; + return devm_gpiochip_add_data(dev, gc, port); } static struct platform_driver vf610_gpio_driver = { -- Gitblit v1.6.2