diff options
Diffstat (limited to 'drivers/gpio/gpio-stp-xway.c')
| -rw-r--r-- | drivers/gpio/gpio-stp-xway.c | 103 |
1 files changed, 68 insertions, 35 deletions
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index 19972084c45b..493c027afdd6 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -1,25 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2012 John Crispin <john@phrozen.org> - * */ +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/module.h> #include <linux/types.h> -#include <linux/of_platform.h> +#include <linux/of.h> #include <linux/mutex.h> #include <linux/gpio/driver.h> #include <linux/io.h> #include <linux/clk.h> #include <linux/err.h> -#include <lantiq_soc.h> - /* * The Serial To Parallel (STP) is found on MIPS based Lantiq socs. It is a * peripheral controller used to drive external shift register cascades. At most @@ -46,7 +42,10 @@ #define XWAY_STP_4HZ BIT(23) #define XWAY_STP_8HZ BIT(24) #define XWAY_STP_10HZ (BIT(24) | BIT(23)) -#define XWAY_STP_SPEED_MASK (0xf << 23) +#define XWAY_STP_SPEED_MASK (BIT(23) | BIT(24) | BIT(25) | BIT(26) | BIT(27)) + +#define XWAY_STP_FPIS_VALUE BIT(21) +#define XWAY_STP_FPIS_MASK (BIT(20) | BIT(21)) /* clock source for automatic update */ #define XWAY_STP_UPD_FPI BIT(31) @@ -59,7 +58,9 @@ /* 2 groups of 3 bits can be driven by the phys */ #define XWAY_STP_PHY_MASK 0x7 #define XWAY_STP_PHY1_SHIFT 27 -#define XWAY_STP_PHY2_SHIFT 15 +#define XWAY_STP_PHY2_SHIFT 3 +#define XWAY_STP_PHY3_SHIFT 6 +#define XWAY_STP_PHY4_SHIFT 15 /* STP has 3 groups of 8 bits */ #define XWAY_STP_GROUP0 BIT(0) @@ -74,8 +75,7 @@ #define xway_stp_r32(m, reg) __raw_readl(m + reg) #define xway_stp_w32(m, val, reg) __raw_writel(val, m + reg) #define xway_stp_w32_mask(m, clear, set, reg) \ - ltq_w32((ltq_r32(m + reg) & ~(clear)) | (set), \ - m + reg) + xway_stp_w32(m, (xway_stp_r32(m, reg) & ~(clear)) | (set), reg) struct xway_stp { struct gpio_chip gc; @@ -86,6 +86,8 @@ struct xway_stp { u8 dsl; /* the 2 LSBs can be driven by the dsl core */ u8 phy1; /* 3 bits can be driven by phy1 */ u8 phy2; /* 3 bits can be driven by phy2 */ + u8 phy3; /* 3 bits can be driven by phy3 */ + u8 phy4; /* 3 bits can be driven by phy4 */ u8 reserved; /* mask out the hw driven bits in gpio_request */ }; @@ -111,7 +113,7 @@ static int xway_stp_get(struct gpio_chip *gc, unsigned int gpio) * * Set the shadow value and call ltq_ebu_apply. */ -static void xway_stp_set(struct gpio_chip *gc, unsigned gpio, int val) +static int xway_stp_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct xway_stp *chip = gpiochip_get_data(gc); @@ -120,7 +122,10 @@ static void xway_stp_set(struct gpio_chip *gc, unsigned gpio, int val) else chip->shadow &= ~BIT(gpio); xway_stp_w32(chip->virt, chip->shadow, XWAY_STP_CPU0); - xway_stp_w32_mask(chip->virt, 0, XWAY_STP_CON_SWU, XWAY_STP_CON0); + if (!chip->reserved) + xway_stp_w32_mask(chip->virt, 0, XWAY_STP_CON_SWU, XWAY_STP_CON0); + + return 0; } /** @@ -133,9 +138,7 @@ static void xway_stp_set(struct gpio_chip *gc, unsigned gpio, int val) */ static int xway_stp_dir_out(struct gpio_chip *gc, unsigned gpio, int val) { - xway_stp_set(gc, gpio, val); - - return 0; + return xway_stp_set(gc, gpio, val); } /** @@ -159,9 +162,9 @@ static int xway_stp_request(struct gpio_chip *gc, unsigned gpio) /** * xway_stp_hw_init() - Configure the STP unit and enable the clock gate - * @virt: pointer to the remapped register range + * @chip: Pointer to the xway_stp chip structure */ -static int xway_stp_hw_init(struct xway_stp *chip) +static void xway_stp_hw_init(struct xway_stp *chip) { /* sane defaults */ xway_stp_w32(chip->virt, 0, XWAY_STP_AR); @@ -194,23 +197,41 @@ static int xway_stp_hw_init(struct xway_stp *chip) chip->phy2 << XWAY_STP_PHY2_SHIFT, XWAY_STP_CON1); + if (of_machine_is_compatible("lantiq,grx390") + || of_machine_is_compatible("lantiq,ar10")) { + xway_stp_w32_mask(chip->virt, + XWAY_STP_PHY_MASK << XWAY_STP_PHY3_SHIFT, + chip->phy3 << XWAY_STP_PHY3_SHIFT, + XWAY_STP_CON1); + } + + if (of_machine_is_compatible("lantiq,grx390")) { + xway_stp_w32_mask(chip->virt, + XWAY_STP_PHY_MASK << XWAY_STP_PHY4_SHIFT, + chip->phy4 << XWAY_STP_PHY4_SHIFT, + XWAY_STP_CON1); + } + /* mask out the hw driven bits in gpio_request */ - chip->reserved = (chip->phy2 << 5) | (chip->phy1 << 2) | chip->dsl; + chip->reserved = (chip->phy4 << 11) | (chip->phy3 << 8) | (chip->phy2 << 5) + | (chip->phy1 << 2) | chip->dsl; /* * if we have pins that are driven by hw, we need to tell the stp what * clock to use as a timer. */ - if (chip->reserved) + if (chip->reserved) { xway_stp_w32_mask(chip->virt, XWAY_STP_UPD_MASK, XWAY_STP_UPD_FPI, XWAY_STP_CON1); - - return 0; + xway_stp_w32_mask(chip->virt, XWAY_STP_SPEED_MASK, + XWAY_STP_10HZ, XWAY_STP_CON1); + xway_stp_w32_mask(chip->virt, XWAY_STP_FPIS_MASK, + XWAY_STP_FPIS_VALUE, XWAY_STP_CON1); + } } static int xway_stp_probe(struct platform_device *pdev) { - struct resource *res; u32 shadow, groups, dsl, phy; struct xway_stp *chip; struct clk *clk; @@ -220,8 +241,7 @@ static int xway_stp_probe(struct platform_device *pdev) if (!chip) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->virt = devm_ioremap_resource(&pdev->dev, res); + chip->virt = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->virt)) return PTR_ERR(chip->virt); @@ -252,32 +272,45 @@ static int xway_stp_probe(struct platform_device *pdev) /* find out which gpios are controlled by the phys */ if (of_machine_is_compatible("lantiq,ar9") || of_machine_is_compatible("lantiq,gr9") || - of_machine_is_compatible("lantiq,vr9")) { + of_machine_is_compatible("lantiq,vr9") || + of_machine_is_compatible("lantiq,ar10") || + of_machine_is_compatible("lantiq,grx390")) { if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy1", &phy)) chip->phy1 = phy & XWAY_STP_PHY_MASK; if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy2", &phy)) chip->phy2 = phy & XWAY_STP_PHY_MASK; } + if (of_machine_is_compatible("lantiq,ar10") || + of_machine_is_compatible("lantiq,grx390")) { + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy3", &phy)) + chip->phy3 = phy & XWAY_STP_PHY_MASK; + } + + if (of_machine_is_compatible("lantiq,grx390")) { + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy4", &phy)) + chip->phy4 = phy & XWAY_STP_PHY_MASK; + } + /* check which edge trigger we should use, default to a falling edge */ - if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL)) + if (!of_property_read_bool(pdev->dev.of_node, "lantiq,rising")) chip->edge = XWAY_STP_FALLING; - clk = clk_get(&pdev->dev, NULL); + clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Failed to get clock\n"); return PTR_ERR(clk); } - clk_enable(clk); - ret = xway_stp_hw_init(chip); - if (!ret) - ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); + xway_stp_hw_init(chip); - if (!ret) - dev_info(&pdev->dev, "Init done\n"); + ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); + if (ret) + return ret; - return ret; + dev_info(&pdev->dev, "Init done\n"); + + return 0; } static const struct of_device_id xway_stp_match[] = { |
