Add gpio/pinconf support to Broadcom Cygnus SoC
Subsystems (4)
Ray Jui
maintainerv9 cover Add gpio/pinconf support to Broadcom Cygnus SoC
This patchset contains the initial GPIO/PINCONF support for the Broadcom Cygnus SoC.
Cygnus has 3 GPIO controllers: 1) the ASIU GPIO; 2) the chipCommonG GPIO; and 3) the ALWAYS-ON GPIO. All 3 types of GPIO controllers are supported by the this driver.
All 3 Cygnus GPIO controllers support basic PINCONF functions such as bias pull up, pull down, and drive strength configurations, when these pins are muxed to GPIO.
Pins from the ASIU GPIO can be individually muxed to GPIO function, through interaction with the Cygnus IOMUX controller.
Note this patchset has a dependency on the other patchset "Add pinctrl support to Broadcom Cygnus SoC" that is also under review
Changes from v8:
- Add code in function 'cygnus_gpio_pinmux_add_range' to free pinmux node resource by calling of_node_put
- Drop .suppress_bind_attrs = true, since this is already done in platform_driver_probe
Changes from v7:
- Use 'bool' instead of 'int' for flag that indicates pinmux support in the driver
- Call put_device to drop reference to the pinmux dev after call to of_find_device_by_node
- Replace kasprintf with devm_kasprintf and remove memory deallocation logic in the driver
- Set suppress_bind_attrs to true for the driver
Changes from v6:
- Move the driver from drivers/gpio/* to drivers/pinctrl/* since this driver supports both GPIO and some basic PINCONF features
- Support PINCONF features through standard DT subnodes properties including "bias-disable", "bias-pull-up", "bias-pull-down", and "drive-strength", by creating local PINCONF controller
- Add support to allow individual ASIU GPIO pins to be muxed as GPIO, through interactions with the Cygnus IOMUX driver
- Convert the driver to use standard GPIOCHIP_IRQ APIs. This helps to reduce customized code in the driver
- Other miscellaneous imrpovements in the driver
- Enable GPIO based phone hook detection support for BCM911360 phone factor board
Changes from v5:
- Get rid of DT property "linux,gpio-base". Use dynamic allocation for GPIO base number
Changes from v4:
- Use DT property "linux,gpio-base" to define GPIO base number
- factorize common code to improve code readability and reduce code size
- remove "bcm_" prefix on function and struct names
- improve debugging prints
- default GPIO_BCM_CYGNUS to y in Kconfig (it still depends on ARCH_BCM_CYGNUS). This way we do not need to select it from the arch/arm/mach-bcm/Kconfig
- Get rid of redundant MAINTAINER entry for this driver. It will be maintained by Broadcom iProc/Cygnus maintainers
- Update device tree document based on driver changes
Changes from v3:
- Fix dt property tpyo
- Fix incorrect GPIO compatible ID in device tree binding document example
Changes from v2:
- Consolidate different compatible IDs into "brcm,cygnus-gpio"
- Get rid of redundant "no-interrupt" property
Changes from v1:
- Get rid of inline qualifier
- Get rid of redundant check in the ISR
- Other minor fixes to imrove code readability
Ray Jui (4):
pinctrl: Cygnus: define Broadcom Cygnus GPIO/PINCONF binding
pinctrl: cygnus: add gpio/pinconf driver
ARM: dts: enable GPIO for Broadcom Cygnus
ARM: dts: cygnus: enable GPIO based hook detection
.../bindings/pinctrl/brcm,cygnus-gpio.txt | 102 +++ arch/arm/boot/dts/bcm-cygnus.dtsi | 33 + arch/arm/boot/dts/bcm911360_entphn.dts | 13 + drivers/pinctrl/bcm/Kconfig | 22 + drivers/pinctrl/bcm/Makefile | 1 + drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c | 908 ++++++++++++++++++++ 6 files changed, 1079 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v9 1/4 pinctrl: Cygnus: define Broadcom Cygnus GPIO/PINCONF binding
Document the GPIO/PINCONF device tree binding for Broadcom Cygnus SoC
--- .../bindings/pinctrl/brcm,cygnus-gpio.txt | 102 ++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt
Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt new file +102 -0
@@ -0,0 +1,102 @@ +Broadcom Cygnus GPIO/PINCONF Controller + +Required properties: + +- compatible: + Must be "brcm,cygnus-gpio" + +- reg: + Define the base and range of the I/O address space that contains the Cygnus +GPIO/PINCONF controller registers + +- ngpios: + Total number of GPIOs the controller provides + +- #gpio-cells: + Must be two. The first cell is the GPIO pin number (within the +controller's pin space) and the second cell is used for the following: + bit[0]: polarity (0 for active high and 1 for active low) + +- gpio-controller: + Specifies that the node is a GPIO controller + +Optional properties: + +- interrupts: + Interrupt ID + +- interrupt-controller: + Specifies that the node is an interrupt controller + +- pinmux: + Specifies the phandle to the IOMUX device, where pins can be individually +muxed to GPIO + +Supported generic PINCONF properties in child nodes: + +- pins: + The list of pins (within the controller's own pin space) that properties +in the node apply to. Pin names are "gpio-<pin>" + +- bias-disable: + Disable pin bias + +- bias-pull-up: + Enable internal pull up resistor + +- bias-pull-down: + Enable internal pull down resistor + +- drive-strength: + Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA) + +Example: + gpio_ccm: gpio@1800a000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x1800a000 0x50>, + <0x0301d164 0x20>; + ngpios = <24>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + + touch_pins: touch_pins { + pwr: pwr { + pins = "gpio-0"; + drive-strength = <16>; + }; + + event: event { + pins = "gpio-1"; + bias-pull-up; + }; + }; + }; + + gpio_asiu: gpio@180a5000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x180a5000 0x668>; + ngpios = <146>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + }; + + /* + * Touchscreen that uses the CCM GPIO 0 and 1 + */ + tsc { + ... + ... + gpio-pwr = <&gpio_ccm 0 0>; + gpio-event = <&gpio_ccm 1 0>; + }; + + /* Bluetooth that uses the ASIU GPIO 5, with polarity inverted */ + bluetooth { + ... + ... + bcm,rfkill-bank-sel = <&gpio_asiu 5 1> + }
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v9 2/4 pinctrl: cygnus: add gpio/pinconf driver
In reply to Ray JuiThis adds the initial support of the Broadcom Cygnus GPIO/PINCONF driver that supports all 3 GPIO controllers on Cygnus including the ASIU GPIO controller, the chipCommonG GPIO controller, and the always-on GPIO controller. Basic PINCONF configurations such as bias pull up/down, and drive strength are also supported in this driver.
Pins from the ASIU GPIO controller can be individually muxed to GPIO function, through interaction with the Cygnus IOMUX controller
--- drivers/pinctrl/bcm/Kconfig | 22 + drivers/pinctrl/bcm/Makefile | 1 + drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c | 908 +++++++++++++++++++++++++++++ 3 files changed, 931 insertions(+) create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
drivers/pinctrl/bcm/Kconfig +22 -0
@@ -20,6 +20,28 @@ config PINCTRL_BCM2835 select PINMUX select PINCONF +config PINCTRL_CYGNUS_GPIO + bool "Broadcom Cygnus GPIO (with PINCONF) driver" + depends on OF_GPIO && ARCH_BCM_CYGNUS + select GPIOLIB_IRQCHIP + select PINCONF + select GENERIC_PINCONF + default ARCH_BCM_CYGNUS + help + Say yes here to enable the Broadcom Cygnus GPIO driver. + + The Broadcom Cygnus SoC has 3 GPIO controllers including the ASIU + GPIO controller (ASIU), the chipCommonG GPIO controller (CCM), and + the always-ON GPIO controller (CRMU/AON). All 3 GPIO controllers are + supported by this driver. + + All 3 Cygnus GPIO controllers support basic PINCONF functions such + as bias pull up, pull down, and drive strength configurations, when + these pins are muxed to GPIO. + + Pins from the ASIU GPIO can be individually muxed to GPIO function, + through interaction with the Cygnus IOMUX controller. + config PINCTRL_CYGNUS_MUX bool "Broadcom Cygnus IOMUX driver" depends on (ARCH_BCM_CYGNUS || COMPILE_TEST)
drivers/pinctrl/bcm/Makefile +1 -0
@@ -2,4 +2,5 @@ obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_CYGNUS_GPIO) += pinctrl-cygnus-gpio.o obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +908 -0
908 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v9 2/4] pinctrl: cygnus: add gpio/pinconf driver
Quoted 11 lines · Ray Jui
This adds the initial support of the Broadcom Cygnus GPIO/PINCONF driver that supports all 3 GPIO controllers on Cygnus including the ASIU GPIO controller, the chipCommonG GPIO controller, and the always-on GPIO controller. Basic PINCONF configurations such as bias pull up/down, and drive strength are also supported in this driver.
Pins from the ASIU GPIO controller can be individually muxed to GPIO function, through interaction with the Cygnus IOMUX controller
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>
OK!
Quoted 1 line
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +0
-0
(...)
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 28
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +6
-0+#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/gpio.h>
This should be:
#include <linux/gpio/driver.h>
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 123
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+static u32 cygnus_readl (struct cygnus_gpio *chip,unsigned int offset) +{ +return readl (chip->base + offset); +} + +static void cygnus_writel (struct cygnus_gpio *chip,unsigned int offset, +u32 val) +{ +writel (val, chip->base + offset); +}
If these look like so, just use readl(val, chip->base + offset)/writel() at all sites.
These functions just adds a pointless layer of abstraction.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 135
Quoted 2 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +2
-0+static void cygnus_set_bit (struct cygnus_gpio *chip,unsigned int reg, +unsigned gpio,int set)
"set" should be bool, right?
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; +
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 150
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+ val =cygnus_readl (chip, offset); +if (set) + val |=BIT (shift); +else + val &= ~BIT (shift); +cygnus_writel (chip, offset, val); +} + +static int cygnus_get_bit (struct cygnus_gpio *chip,unsigned int reg, +unsigned gpio)
This should be bool right, not int?
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 160
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + val = + if (val) +return 1 ; + else + return 0;
Just:
return !!(cygnus_readl(chip, offset) & BIT(shift));
Both of these are a bit overzealous like the readl/writel functions above, consider just inlining them.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 252
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +6
-0+static int cygnus_gpio_irq_set_type (struct irq_data *d,unsigned int type) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = d->hwirq; +int int_type =0 , dual_edge =0 , edge_lvl =0 ;
It looks like some of these should be bool.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 257
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+unsigned long flags; + +switch (type &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_EDGE_RISING : + edge_lvl =1 ;
= true;
etc.
Quoted 37 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +37
-0+break ; + +case IRQ_TYPE_EDGE_FALLING : +break ; + +case IRQ_TYPE_EDGE_BOTH : + dual_edge =1 ; +break ; + +case IRQ_TYPE_LEVEL_HIGH : + int_type =1 ; + edge_lvl =1 ; +break ; + +case IRQ_TYPE_LEVEL_LOW : + int_type =1 ; +break ; + +default : +dev_err (chip->dev,"invalid GPIO IRQ type 0x%x\n" , + type); +return -EINVAL ; + } + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_IN_TYPE_OFFSET , gpio, int_type); +cygnus_set_bit (chip,CYGNUS_GPIO_INT_DE_OFFSET , gpio, dual_edge); +cygnus_set_bit (chip,CYGNUS_GPIO_INT_EDGE_OFFSET , gpio, + edge_lvl); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev, +"gpio:%u set int_type:%d dual_edge:%d edge_lvl:%d\n" , + gpio, int_type, dual_edge, edge_lvl); + +return 0 ; +}
(...)
Quoted 15 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +15
-0+/* +* Request the Cygnus IOMUX pinmux controller to mux individual pins to GPIO +*/ +static int cygnus_gpio_request (struct gpio_chip *gc,unsigned offset) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = gc->base + offset; + +/* not all Cygnus GPIO pins can be muxed individually */ +if (!chip->pinmux_is_supported) +return 0 ; + +return pinctrl_request_gpio (gpio); +} +
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 328
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+static void cygnus_gpio_free (struct gpio_chip *gc,unsigned offset) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = gc->base + offset; + +if (!chip->pinmux_is_supported) +return ; + +pinctrl_free_gpio (gpio); +}
Nice!
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 611
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+static const struct pinconf_ops cygnus_pconf_ops = { + .is_generic = true, + .pin_config_get = cygnus_pin_config_get, + .pin_config_set = cygnus_pin_config_set, +};
This pin config thing looks really nice.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 623
Quoted 11 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +11
-0+/* +* Map a GPIO in the local gpio_chip pin space to a pin in the Cygnus IOMUX +* pinctrl pin space +*/ +struct cygnus_gpio_pin_range { +unsigned offset; +unsigned pin_base; +unsigned num_pins; +}; + +#define CYGNUS_PINRANGE (o, p, n) { .offset = o, .pin_base = p, .num_pins = n }
Aha so this mapping is really very sparse...
Quoted 84 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +84
-0+/* +* Pin mapping table for mapping local GPIO pins to Cygnus IOMUX pinctrl pins +*/ +static const struct cygnus_gpio_pin_range cygnus_gpio_pintable[] = { +CYGNUS_PINRANGE (0 ,42 ,1 ), +CYGNUS_PINRANGE (1 ,44 ,3 ), +CYGNUS_PINRANGE (4 ,48 ,1 ), +CYGNUS_PINRANGE (5 ,50 ,3 ), +CYGNUS_PINRANGE (8 ,126 ,1 ), +CYGNUS_PINRANGE (9 ,155 ,1 ), +CYGNUS_PINRANGE (10 ,152 ,1 ), +CYGNUS_PINRANGE (11 ,154 ,1 ), +CYGNUS_PINRANGE (12 ,153 ,1 ), +CYGNUS_PINRANGE (13 ,127 ,3 ), +CYGNUS_PINRANGE (16 ,140 ,1 ), +CYGNUS_PINRANGE (17 ,145 ,7 ), +CYGNUS_PINRANGE (24 ,130 ,10 ), +CYGNUS_PINRANGE (34 ,141 ,4 ), +CYGNUS_PINRANGE (38 ,54 ,1 ), +CYGNUS_PINRANGE (39 ,56 ,3 ), +CYGNUS_PINRANGE (42 ,60 ,3 ), +CYGNUS_PINRANGE (45 ,64 ,3 ), +CYGNUS_PINRANGE (48 ,68 ,2 ), +CYGNUS_PINRANGE (50 ,84 ,6 ), +CYGNUS_PINRANGE (56 ,94 ,6 ), +CYGNUS_PINRANGE (62 ,72 ,1 ), +CYGNUS_PINRANGE (63 ,70 ,1 ), +CYGNUS_PINRANGE (64 ,80 ,1 ), +CYGNUS_PINRANGE (65 ,74 ,3 ), +CYGNUS_PINRANGE (68 ,78 ,1 ), +CYGNUS_PINRANGE (69 ,82 ,1 ), +CYGNUS_PINRANGE (70 ,156 ,17 ), +CYGNUS_PINRANGE (87 ,104 ,12 ), +CYGNUS_PINRANGE (99 ,102 ,2 ), +CYGNUS_PINRANGE (101 ,90 ,4 ), +CYGNUS_PINRANGE (105 ,116 ,10 ), +CYGNUS_PINRANGE (123 ,11 ,1 ), +CYGNUS_PINRANGE (124 ,38 ,4 ), +CYGNUS_PINRANGE (128 ,43 ,1 ), +CYGNUS_PINRANGE (129 ,47 ,1 ), +CYGNUS_PINRANGE (130 ,49 ,1 ), +CYGNUS_PINRANGE (131 ,53 ,1 ), +CYGNUS_PINRANGE (132 ,55 ,1 ), +CYGNUS_PINRANGE (133 ,59 ,1 ), +CYGNUS_PINRANGE (134 ,63 ,1 ), +CYGNUS_PINRANGE (135 ,67 ,1 ), +CYGNUS_PINRANGE (136 ,71 ,1 ), +CYGNUS_PINRANGE (137 ,73 ,1 ), +CYGNUS_PINRANGE (138 ,77 ,1 ), +CYGNUS_PINRANGE (139 ,79 ,1 ), +CYGNUS_PINRANGE (140 ,81 ,1 ), +CYGNUS_PINRANGE (141 ,83 ,1 ), +CYGNUS_PINRANGE (142 ,10 ,1 ) +}; + +/* +* The Cygnus IOMUX controller mainly supports group based mux configuration, +* but certain pins can be muxed to GPIO individually. Only the ASIU GPIO +* controller can support this, so it's an optional configuration +* +* Return -ENODEV means no support and that's fine +*/ +static int cygnus_gpio_pinmux_add_range (struct cygnus_gpio *chip) +{ +struct device_node *node = chip->dev->of_node; +struct device_node *pinmux_node; +struct platform_device *pinmux_pdev; +struct gpio_chip *gc = &chip->gc; +int i, ret =0 ; + +/* parse DT to find the phandle to the pinmux controller */ + pinmux_node =of_parse_phandle (node,"pinmux" ,0 ); +if (!pinmux_node) +return -ENODEV ; + + pinmux_pdev =of_find_device_by_node (pinmux_node); +/* no longer need the pinmux node */ +of_node_put (pinmux_node); +if (!pinmux_pdev) { +dev_err (chip->dev,"failed to get pinmux device\n" ); +return -EINVAL ; + } + +/* now need to create the mapping between local GPIO and PINMUX pins */
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 718
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+for (i =0 ; i <ARRAY_SIZE (cygnus_gpio_pintable); i++) { + ret =gpiochip_add_pin_range (gc,dev_name (&pinmux_pdev->dev), + cygnus_gpio_pintable[i].offset, + cygnus_gpio_pintable[i].pin_base, + cygnus_gpio_pintable[i].num_pins); +if (ret) { +dev_err (chip->dev,"unable to add GPIO pin range\n" ); + goto err_put_device; + } + }
This is really nice. Awesome job, exactly how it should be done, even if it's a bit complex.
Quoted 1 line
+
chip->pinmux_is_supported= (ret == 0);
Just = true;
You cannot get here with ret != 0.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 738
Quoted 7 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +7
-0+static void cygnus_gpio_pinmux_remove_range (struct cygnus_gpio *chip) +{ +struct gpio_chip *gc = &chip->gc; + +if (chip->pinmux_is_supported) +gpiochip_remove_pin_ranges (gc); +}
You don't need to do this. Look in gpiochip_remove() and you see it will remove the range for you.
+
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 884
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+err_unregister_pinconf: +cygnus_gpio_unregister_pinconf (chip); + +err_rm_range: +cygnus_gpio_pinmux_remove_range (chip);
Not needed I think.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 887
Quoted 3 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +3
-0+ +err_rm_gpiochip: +gpiochip_remove (gc);
Because this will do it.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 554
Quoted 3 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +3
-0+ +return ret; +}
Apart from that this looks really good!
If you resend with the above nitpicks fixed I will merge this.
Yours,
Linus Walleij
Ray Jui
maintainerRe: [PATCH v9 2/4] pinctrl: cygnus: add gpio/pinconf driver
Hi Linus,
Quoted 328 lines · Linus Walleij
Quoted 11 lines · Ray Jui
This adds the initial support of the Broadcom Cygnus GPIO/PINCONF driver that supports all 3 GPIO controllers on Cygnus including the ASIU GPIO controller, the chipCommonG GPIO controller, and the always-on GPIO controller. Basic PINCONF configurations such as bias pull up/down, and drive strength are also supported in this driver.
Pins from the ASIU GPIO controller can be individually muxed to GPIO function, through interaction with the Cygnus IOMUX controller
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>OK!
Quoted 1 line
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +0
-0(...)
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 28
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +6
-0+#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/gpio.h> This should be:
#include <linux/gpio/driver.h>drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 123
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+static u32 cygnus_readl (struct cygnus_gpio *chip,unsigned int offset) +{ +return readl (chip->base + offset); +} + +static void cygnus_writel (struct cygnus_gpio *chip,unsigned int offset, +u32 val) +{ +writel (val, chip->base + offset); +}If these look like so, just use
readl(val, chip->base + offset)/writel() at all sites.
These functions just adds a pointless layer of abstraction.drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 135
Quoted 2 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +2
-0+static void cygnus_set_bit (struct cygnus_gpio *chip,unsigned int reg, +unsigned gpio,int set)"set" should be bool, right?
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; +drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 150
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+ val =cygnus_readl (chip, offset); +if (set) + val |=BIT (shift); +else + val &= ~BIT (shift); +cygnus_writel (chip, offset, val); +} + +static int cygnus_get_bit (struct cygnus_gpio *chip,unsigned int reg, +unsigned gpio)This should be bool right, not int?
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 160
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + val = + if (val) +return 1 ; + else + return 0;Just:
return !!(cygnus_readl(chip, offset) & BIT(shift));Both of these are a bit overzealous like the readl/writel functions above, consider just inlining them.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 252
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +6
-0+static int cygnus_gpio_irq_set_type (struct irq_data *d,unsigned int type) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = d->hwirq; +int int_type =0 , dual_edge =0 , edge_lvl =0 ;It looks like some of these should be bool.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 257
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+unsigned long flags; + +switch (type &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_EDGE_RISING : + edge_lvl =1 ;= true;
etc.
Quoted 37 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +37
-0+break ; + +case IRQ_TYPE_EDGE_FALLING : +break ; + +case IRQ_TYPE_EDGE_BOTH : + dual_edge =1 ; +break ; + +case IRQ_TYPE_LEVEL_HIGH : + int_type =1 ; + edge_lvl =1 ; +break ; + +case IRQ_TYPE_LEVEL_LOW : + int_type =1 ; +break ; + +default : +dev_err (chip->dev,"invalid GPIO IRQ type 0x%x\n" , + type); +return -EINVAL ; + } + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_IN_TYPE_OFFSET , gpio, int_type); +cygnus_set_bit (chip,CYGNUS_GPIO_INT_DE_OFFSET , gpio, dual_edge); +cygnus_set_bit (chip,CYGNUS_GPIO_INT_EDGE_OFFSET , gpio, + edge_lvl); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev, +"gpio:%u set int_type:%d dual_edge:%d edge_lvl:%d\n" , + gpio, int_type, dual_edge, edge_lvl); + +return 0 ; +}(...)
Quoted 15 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +15
-0+/* +* Request the Cygnus IOMUX pinmux controller to mux individual pins to GPIO +*/ +static int cygnus_gpio_request (struct gpio_chip *gc,unsigned offset) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = gc->base + offset; + +/* not all Cygnus GPIO pins can be muxed individually */ +if (!chip->pinmux_is_supported) +return 0 ; + +return pinctrl_request_gpio (gpio); +} +drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 328
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+static void cygnus_gpio_free (struct gpio_chip *gc,unsigned offset) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = gc->base + offset; + +if (!chip->pinmux_is_supported) +return ; + +pinctrl_free_gpio (gpio); +}Nice!
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 611
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+static const struct pinconf_ops cygnus_pconf_ops = { + .is_generic = true, + .pin_config_get = cygnus_pin_config_get, + .pin_config_set = cygnus_pin_config_set, +};This pin config thing looks really nice.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 623
Quoted 11 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +11
-0+/* +* Map a GPIO in the local gpio_chip pin space to a pin in the Cygnus IOMUX +* pinctrl pin space +*/ +struct cygnus_gpio_pin_range { +unsigned offset; +unsigned pin_base; +unsigned num_pins; +}; + +#define CYGNUS_PINRANGE (o, p, n) { .offset = o, .pin_base = p, .num_pins = n }Aha so this mapping is really very sparse...
Quoted 84 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +84
-0+/* +* Pin mapping table for mapping local GPIO pins to Cygnus IOMUX pinctrl pins +*/ +static const struct cygnus_gpio_pin_range cygnus_gpio_pintable[] = { +CYGNUS_PINRANGE (0 ,42 ,1 ), +CYGNUS_PINRANGE (1 ,44 ,3 ), +CYGNUS_PINRANGE (4 ,48 ,1 ), +CYGNUS_PINRANGE (5 ,50 ,3 ), +CYGNUS_PINRANGE (8 ,126 ,1 ), +CYGNUS_PINRANGE (9 ,155 ,1 ), +CYGNUS_PINRANGE (10 ,152 ,1 ), +CYGNUS_PINRANGE (11 ,154 ,1 ), +CYGNUS_PINRANGE (12 ,153 ,1 ), +CYGNUS_PINRANGE (13 ,127 ,3 ), +CYGNUS_PINRANGE (16 ,140 ,1 ), +CYGNUS_PINRANGE (17 ,145 ,7 ), +CYGNUS_PINRANGE (24 ,130 ,10 ), +CYGNUS_PINRANGE (34 ,141 ,4 ), +CYGNUS_PINRANGE (38 ,54 ,1 ), +CYGNUS_PINRANGE (39 ,56 ,3 ), +CYGNUS_PINRANGE (42 ,60 ,3 ), +CYGNUS_PINRANGE (45 ,64 ,3 ), +CYGNUS_PINRANGE (48 ,68 ,2 ), +CYGNUS_PINRANGE (50 ,84 ,6 ), +CYGNUS_PINRANGE (56 ,94 ,6 ), +CYGNUS_PINRANGE (62 ,72 ,1 ), +CYGNUS_PINRANGE (63 ,70 ,1 ), +CYGNUS_PINRANGE (64 ,80 ,1 ), +CYGNUS_PINRANGE (65 ,74 ,3 ), +CYGNUS_PINRANGE (68 ,78 ,1 ), +CYGNUS_PINRANGE (69 ,82 ,1 ), +CYGNUS_PINRANGE (70 ,156 ,17 ), +CYGNUS_PINRANGE (87 ,104 ,12 ), +CYGNUS_PINRANGE (99 ,102 ,2 ), +CYGNUS_PINRANGE (101 ,90 ,4 ), +CYGNUS_PINRANGE (105 ,116 ,10 ), +CYGNUS_PINRANGE (123 ,11 ,1 ), +CYGNUS_PINRANGE (124 ,38 ,4 ), +CYGNUS_PINRANGE (128 ,43 ,1 ), +CYGNUS_PINRANGE (129 ,47 ,1 ), +CYGNUS_PINRANGE (130 ,49 ,1 ), +CYGNUS_PINRANGE (131 ,53 ,1 ), +CYGNUS_PINRANGE (132 ,55 ,1 ), +CYGNUS_PINRANGE (133 ,59 ,1 ), +CYGNUS_PINRANGE (134 ,63 ,1 ), +CYGNUS_PINRANGE (135 ,67 ,1 ), +CYGNUS_PINRANGE (136 ,71 ,1 ), +CYGNUS_PINRANGE (137 ,73 ,1 ), +CYGNUS_PINRANGE (138 ,77 ,1 ), +CYGNUS_PINRANGE (139 ,79 ,1 ), +CYGNUS_PINRANGE (140 ,81 ,1 ), +CYGNUS_PINRANGE (141 ,83 ,1 ), +CYGNUS_PINRANGE (142 ,10 ,1 ) +}; + +/* +* The Cygnus IOMUX controller mainly supports group based mux configuration, +* but certain pins can be muxed to GPIO individually. Only the ASIU GPIO +* controller can support this, so it's an optional configuration +* +* Return -ENODEV means no support and that's fine +*/ +static int cygnus_gpio_pinmux_add_range (struct cygnus_gpio *chip) +{ +struct device_node *node = chip->dev->of_node; +struct device_node *pinmux_node; +struct platform_device *pinmux_pdev; +struct gpio_chip *gc = &chip->gc; +int i, ret =0 ; + +/* parse DT to find the phandle to the pinmux controller */ + pinmux_node =of_parse_phandle (node,"pinmux" ,0 ); +if (!pinmux_node) +return -ENODEV ; + + pinmux_pdev =of_find_device_by_node (pinmux_node); +/* no longer need the pinmux node */ +of_node_put (pinmux_node); +if (!pinmux_pdev) { +dev_err (chip->dev,"failed to get pinmux device\n" ); +return -EINVAL ; + } + +/* now need to create the mapping between local GPIO and PINMUX pins */ drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 718
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +10
-0+for (i =0 ; i <ARRAY_SIZE (cygnus_gpio_pintable); i++) { + ret =gpiochip_add_pin_range (gc,dev_name (&pinmux_pdev->dev), + cygnus_gpio_pintable[i].offset, + cygnus_gpio_pintable[i].pin_base, + cygnus_gpio_pintable[i].num_pins); +if (ret) { +dev_err (chip->dev,"unable to add GPIO pin range\n" ); + goto err_put_device; + } + }This is really nice. Awesome job, exactly how it should be done, even if it's a bit complex.
Quoted 1 line
+
chip->pinmux_is_supported= (ret == 0);Just = true;
You cannot get here with ret != 0.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 738
Quoted 7 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +7
-0+static void cygnus_gpio_pinmux_remove_range (struct cygnus_gpio *chip) +{ +struct gpio_chip *gc = &chip->gc; + +if (chip->pinmux_is_supported) +gpiochip_remove_pin_ranges (gc); +}You don't need to do this. Look in
gpiochip_remove()and you see it will remove the range for you.+
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 884
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +5
-0+err_unregister_pinconf: +cygnus_gpio_unregister_pinconf (chip); + +err_rm_range: +cygnus_gpio_pinmux_remove_range (chip);Not needed I think.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 887
Quoted 3 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +3
-0+ +err_rm_gpiochip: +gpiochip_remove (gc);Because this will do it.
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 554
Quoted 3 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c +3
-0+ +return ret; +}Apart from that this looks really good!
Quoted 5 lines
If you resend with the above nitpicks fixed I will merge this.
Yours,
Linus Walleij
Great! I will address all comments and re-send a BIG patch series with the other pinctrl patch series consolidated.
Thanks!
Ray
Ray Jui
maintainerRe: [PATCH v9 2/4] pinctrl: cygnus: add gpio/pinconf driver
Hi Linus,
Quoted 9 lines
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 28
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +6
-0+#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/gpio.h> This should be:
#include <linux/gpio/driver.h>
In fact, just by trying it out I found I need linux/gpio.h for APIs like gpiochip_add_pin_range, and etc.
Quoted 10 lines
Quoted 2 lines
Great! I will address all comments and re-send a BIG patch series with the other pinctrl patch series consolidated.
Thanks!
Ray
I've consolidated this patch series with the IOMUX and sent out a combined patch series earlier. I believe all other comments have been addressed except the above include header one.
Thanks,
Ray
Ray Jui
maintainerPATCH v9 3/4 ARM: dts: enable GPIO for Broadcom Cygnus
In reply to Ray JuiThis enables all 3 GPIO controllers including the ASIU GPIO, the chipcommonG GPIO, and the ALWAYS-ON GPIO, for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +33 -0
@@ -60,6 +60,39 @@ <0x0301d24c 0x2c>; }; + gpio_crmu: gpio@03024800 { + compatible = "brcm,cygnus-gpio"; + reg = <0x03024800 0x50>, + <0x03024008 0x18>; + ngpios = <6>; + #gpio-cells = <2>; + gpio-controller; + }; + + gpio_ccm: gpio@1800a000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x1800a000 0x50>, + <0x0301d164 0x20>; + ngpios = <24>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + }; + + gpio_asiu: gpio@180a5000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x180a5000 0x668>; + ngpios = <146>; + #gpio-cells = <2>; + gpio-controller; + + pinmux = <&pinctrl>; + + interrupt-controller; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + }; + amba { #address-cells = <1>; #size-cells = <1>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v9 4/4 ARM: dts: cygnus: enable GPIO based hook detection
In reply to Ray JuiThis enables GPIO based phone hook detection for Broadcom BCM911360 phone factor board (bcm911360_entphn)
--- arch/arm/boot/dts/bcm911360_entphn.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+)
arch/arm/boot/dts/bcm911360_entphn.dts +13 -0
@@ -33,6 +33,7 @@ /dts-v1/; #include "bcm-cygnus.dtsi" +#include "dt-bindings/input/input.h" / { model = "Cygnus Enterprise Phone (BCM911360_ENTPHN)";
@@ -50,4 +51,16 @@ uart3: serial@18023000 { status = "okay"; }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + hook { + label = "HOOK"; + linux,code = <KEY_O>; + gpios = <&gpio_asiu 48 0>; + }; + }; };
Signature · 1 line
1.7.9.5
Quoted 66 lines · Ray Jui
This patchset contains the initial GPIO/PINCONF support for the Broadcom Cygnus SoC.
Cygnus has 3 GPIO controllers: 1) the ASIU GPIO; 2) the chipCommonG GPIO; and 3) the ALWAYS-ON GPIO. All 3 types of GPIO controllers are supported by the this driver.
All 3 Cygnus GPIO controllers support basic PINCONF functions such as bias pull up, pull down, and drive strength configurations, when these pins are muxed to GPIO.
Pins from the ASIU GPIO can be individually muxed to GPIO function, through interaction with the Cygnus IOMUX controller.
Note this patchset has a dependency on the other patchset "Add pinctrl support to Broadcom Cygnus SoC" that is also under review
Changes from v8:
- Add code in function 'cygnus_gpio_pinmux_add_range' to free pinmux node resource by callingof_node_put
- Drop .suppress_bind_attrs = true, since this is already done inplatform_driver_probeChanges from v7:
- Use 'bool' instead of 'int' for flag that indicates pinmux support in the driver
- Callput_deviceto drop reference to the pinmux dev after call toof_find_device_by_node
- Replace kasprintf withdevm_kasprintfand remove memory deallocation logic in the driver
- Setsuppress_bind_attrsto true for the driverChanges from v6:
- Move the driver fromdrivers/gpio/*todrivers/pinctrl/*since this driver supports both GPIO and some basic PINCONF features
- Support PINCONF features through standard DT subnodes properties including "bias-disable", "bias-pull-up", "bias-pull-down", and "drive-strength", by creating local PINCONF controller
- Add support to allow individual ASIU GPIO pins to be muxed as GPIO, through interactions with the Cygnus IOMUX driver
- Convert the driver to use standardGPIOCHIP_IRQAPIs. This helps to reduce customized code in the driver
- Other miscellaneous imrpovements in the driver
- Enable GPIO based phone hook detection support for BCM911360 phone factor boardChanges from v5:
- Get rid of DT property "linux,gpio-base". Use dynamic allocation for GPIO base numberChanges from v4:
- Use DT property "linux,gpio-base" to define GPIO base number
- factorize common code to improve code readability and reduce code size
- remove "bcm_" prefix on function and struct names
- improve debugging prints
- defaultGPIO_BCM_CYGNUSto y inKconfig(it still depends onARCH_BCM_CYGNUS). This way we do not need to select it from thearch/arm/mach-bcm/Kconfig
- Get rid of redundant MAINTAINER entry for this driver. It will be maintained by Broadcom iProc/Cygnus maintainers
- Update device tree document based on driver changesChanges from v3:
- Fix dt property tpyo
- Fix incorrect GPIO compatible ID in device tree binding document example
Quoted 8 lines
Changes from v2:
- Consolidate different compatible IDs into "brcm,cygnus-gpio"
- Get rid of redundant "no-interrupt" propertyChanges from v1:
- Get rid of inline qualifier
- Get rid of redundant check in the ISR
- Other minor fixes to imrove code readability
FWIW I tested this series on BCM958305K SVK.
Thanks.
Signature · 1 line
Dmitry