serial: 8250_dw: Add DMA support for non-ACPI platforms
Subsystems (18)
Ray Jui
maintainerPATCH v3 2/4 pinctrl: Broadcom Cygnus pinctrl device tree binding
In reply to Ray JuiDevice tree binding documentation for Broadcom Cygnus IOMUX driver
--- .../bindings/pinctrl/brcm,cygnus-pinmux.txt | 159 ++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt
Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt new file +159 -0
@@ -0,0 +1,159 @@ +Broadcom Cygnus IOMUX Controller + +The Cygnus IOMUX controller supports group based mux configuration. In +addition, certain pins can be muxed to GPIO function individually. + +Required properties: + +- compatible: + Must be "brcm,cygnus-pinmux" + +- reg: + Define the base and range of the I/O address space that contains the Cygnus +IOMUX registers + +Required properties in child nodes: + +- function: + The mux function to select + +- groups: + The list of groups to select with a given function + +Each child node represents a configuration. Client devices reference the child +node to enable a mux configuration + +For more details, refer to +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +For example: + + pinmux: pinmux at 0x0301d0c8 { + compatible = "brcm,cygnus-pinmux"; + reg = <0x0301d0c8 0x1b0>; + + i2s_0: i2s_0 { + function = "i2s0"; + groups = "i2s0_0_grp", "i2s0_1_grp"; + }; + + i2s_1: i2s_1 { + function = "i2s1"; + groups = "i2s1_0_grp", "i2s1_1_grp"; + }; + + i2s_2: i2s_2 { + function = "i2s2"; + groups = "i2s2_0_grp", "i2s2_1_grp", "i2s2_2_grp", + "i2s2_3_grp", "i2s2_4_grp"; + }; + + spi_0: spi_0 { + function = "spi0"; + groups = "spi0_grp"; + }; + } + + spi0 at 18028000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x18028000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-0 = <&spi_0>; + clocks = <&axi81_clk>; + clock-names = "apb_pclk"; + }; + +List of supported functions and groups in Cygnus: + +"gpio": N/A (to be removed for A0) + +"i2s0": "i2s0_0_grp", "i2s0_1_grp" + +"i2s1": "i2s1_0_grp", "i2s1_1_grp" + +"i2s2": "i2s2_0_grp", "i2s2_1_grp", "i2s2_2_grp", "i2s2_3_grp", "i2s2_4_grp" + +"spdif": "spdif_grp" + +"pwm0": "pwm0_grp" + +"pwm1": "pwm1_grp" + +"pwm2": "pwm2_grp" + +"pwm3": "pwm3_grp" + +"pwm4": "pwm4_grp" + +"pwm5": "pwm5_grp" + +"key": "key0_grp", "key1_grp", "key2_grp", "key3_grp", "key4_grp", "key5_grp", +"key6_grp", "key7_grp", "key8_grp", "key9_grp", "key10_grp", "key11_grp", +"key12_grp", "key13_grp", "key14_grp", "key15_grp" + +"audio_dte": "audio_dte0_grp", "audio_dte1_grp", "audio_dte2_grp", "audio_dte3_grp" + +"smart_card0": "smart_card0_grp", "smart_card0_fcb_grp" + +"smart_card1": "smart_card1_grp", "smart_card1_fcb_grp" + +"spi0": "spi0_grp" + +"spi1": "spi1_grp" + +"spi2": "spi2_grp" + +"spi3": "spi3_grp" + +"spi4": "spi4_0_grp", "spi4_1_grp" + +"spi5": "spi5_grp" + +"sw_led0": "sw_led0_0_grp", "sw_led0_1_grp" + +"sw_led1": "sw_led1_grp" + +"sw_led2": "sw_led2_0_grp", "sw_led2_1_grp" + +"d1w": "d1w_grp" + +"lcd": "lcd_grp" + +"sram": "sram_0_grp", "sram_1_grp" + +"uart0": "uart0_grp" + +"uart1": "uart1_grp", "uart1_dte_grp" + +"uart2": "uart2_grp" + +"uart3": "uart3_grp" + +"uart4": "uart4_grp" + +"qspi": "qspi_0_grp", "qspi_1_grp" + +"nand": "nand_grp" + +"sdio0": "sdio0_grp", "sdio0_cd_grp", "sdio0_mmc_grp" + +"sdio1": "sdio1_data_0_grp", "sdio1_data_1_grp", "sdio1_cd_grp", +"sdio1_led_grp", "sdio1_mmc_grp" + +"can0": "can0_grp" + +"can1": "can1_grp" + +"cam": "cam_led_grp", "cam_0_grp", "cam_1_grp" + +"bsc1": "bsc1_grp" + +"pcie_clkreq": "pcie_clkreq_grp" + +"usb0_oc": "usb0_oc_grp" + +"usb1_oc": "usb1_oc_grp" + +"usb2_oc": "usb2_oc_grp"
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 3/4 pinctrl: cygnus: add initial IOMUX driver support
In reply to Ray JuiThis adds the initial driver support for the Broadcom Cygnus IOMUX controller. The Cygnus IOMUX controller supports group based mux configuration but allows certain pins to be muxed to GPIO individually
--- drivers/pinctrl/bcm/Kconfig | 13 + drivers/pinctrl/bcm/Makefile | 5 +- drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 1087 ++++++++++++++++++++++++++++++ 3 files changed, 1103 insertions(+), 2 deletions(-) create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
drivers/pinctrl/bcm/Kconfig +13 -0
@@ -19,3 +19,16 @@ config PINCTRL_BCM2835 bool select PINMUX select PINCONF + +config PINCTRL_CYGNUS_MUX + bool "Broadcom Cygnus IOMUX driver" + depends on (ARCH_BCM_CYGNUS || COMPILE_TEST) + select PINMUX + select GENERIC_PINCONF + default ARCH_BCM_CYGNUS + help + Say yes here to enable the Broadcom Cygnus IOMUX driver. + + The Broadcom Cygnus IOMUX driver supports group based IOMUX + configuration, with the exception that certain individual pins + can be overrided to GPIO function
drivers/pinctrl/bcm/Makefile +3 -2
@@ -1,4 +1,5 @@ # Broadcom pinctrl support -obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o -obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o +obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +1087 -0
1,087 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v3 3/4] pinctrl: cygnus: add initial IOMUX driver support
Hi Ray,
Quoted 6 lines · Ray Jui
This adds the initial driver support for the Broadcom Cygnus IOMUX controller. The Cygnus IOMUX controller supports group based mux configuration but allows certain pins to be muxed to GPIO individually
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>
Just a few random nits/comments...
Quoted 109 lines
--- drivers/pinctrl/bcm/Kconfig | 13 + drivers/pinctrl/bcm/Makefile | 5 +- drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 1087 ++++++++++++++++++++++++++++++ 3 files changed, 1103 insertions(+), 2 deletions(-) create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-mux.cdrivers/pinctrl/bcm/Kconfig +13
-0@@ -19,3 +19,16 @@ config PINCTRL_BCM2835 bool select PINMUX select PINCONF + +config PINCTRL_CYGNUS_MUX + bool "Broadcom Cygnus IOMUX driver" + depends on (ARCH_BCM_CYGNUS || COMPILE_TEST) + select PINMUX + select GENERIC_PINCONF + default ARCH_BCM_CYGNUS + help + Say yes here to enable the Broadcom Cygnus IOMUX driver. + + The Broadcom Cygnus IOMUX driver supports group based IOMUX + configuration, with the exception that certain individual pins + can be overrided to GPIO functiondrivers/pinctrl/bcm/Makefile +3
-2@@ -1,4 +1,5 @@ # Broadcom pinctrl support -obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o -obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o +obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.odrivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +63
-0@@ -0,0 +1,1087 @@ +/* Copyright (C) 2014-2015 Broadcom Corporation +* +* 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 version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This file contains the Cygnus IOMUX driver that supports group based PINMUX +* configuration. Although PINMUX configuration is mainly group based, the +* Cygnus IOMUX controller allows certain pins to be individually muxed to GPIO +* function, and therefore be controlled by the Cygnus ASIU GPIO controller +*/ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include "../core.h" +#include "../pinctrl-utils.h" + +#define CYGNUS_NUM_IOMUX_REGS 8 +#define CYGNUS_NUM_MUX_PER_REG 8 +#define CYGNUS_NUM_IOMUX (CYGNUS_NUM_IOMUX_REGS * \ + CYGNUS_NUM_MUX_PER_REG) + +/* +* Cygnus IOMUX register description +* +* @offset: register offset for mux configuration of a group +* @shift: bit shift for mux configuration of a group +* @alt: alternate function to set to +*/ +struct cygnus_mux { +unsigned int offset; +unsigned int shift; +unsigned int alt; +}; + +/* +* Keep track of Cygnus IOMUX configuration and prevent double configuration +* +* @cygnus_mux: Cygnus IOMUX register description +* @is_configured: flag to indicate whether a mux setting has already been +* configured +*/ +struct cygnus_mux_log { +struct cygnus_mux mux; +bool is_configured; +}; + +/* +* Group based IOMUX configuration +*
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 73
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +10
-0+* @name: name of the group +* @pins: array of pins used by this group +* @num_pins: total number of pins used by this group +* @mux: Cygnus group based IOMUX configuration +*/ +struct cygnus_pin_group { +const char *name; +const unsigned *pins; +const unsigned num_pins; +const struct cygnus_mux mux;
Not: the last 2 consts are quite weird - if you want to make an instance of cygnus_pin_group immutable you declare it as a const (and I see you are already doing that below). With the structure as it laid out currently you can only do static initializers.
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 86
Quoted 13 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +13
-0+}; + +/* +* Cygnus mux function and supported pin groups +* +* @name: name of the function +* @groups: array of groups that can be supported by this function +* @num_groups: total number of groups that can be supported by this function +*/ +struct cygnus_pin_function { +const char *name; +const char *const *groups; +const unsigned num_groups;
Here as well.
...
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 160
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +5
-0+ +/* +* List of pins in Cygnus +*/ +static struct cygnus_pin cygnus_pins[] = {
const?
Quoted 2 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +2
-0+CYGNUS_PIN_DESC (0 ,"ext_device_reset_n" ,0 ,0 ,0 ), + CYGNUS_PIN_DESC(1, "chip_mode0", 0, 0, 0),
...
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 482
Quoted 3 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +3
-0+#define CYGNUS_PIN_GROUP (group_name, off, sh, al) \ +{ \ + .name = #group_name"""_grp", \
Why do we need extra pair of quotes? BTW we can also do
.name = __stringify(group_name) "_grp",
Quoted 8 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +8
-0+ .pins = group_name ## _pins, \ + .num_pins = ARRAY_SIZE(group_name ## _pins), \ + .mux = { \ + .offset = off, \ + .shift = sh, \ + .alt = al, \ + } \ +}
...
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 800
Quoted 2 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +2
-0+ +static struct pinctrl_ops cygnus_pinctrl_ops = {
const?
Quoted 104 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +104
-0+ .get_groups_count = cygnus_get_groups_count, + .get_group_name = cygnus_get_group_name, + .get_group_pins = cygnus_get_group_pins, + .pin_dbg_show = cygnus_pin_dbg_show, + .dt_node_to_map = cygnus_dt_node_to_map, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int cygnus_get_functions_count (struct pinctrl_dev *pctrl_dev) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); + +return pinctrl->num_functions; +} + +static const char *cygnus_get_function_name (struct pinctrl_dev *pctrl_dev, +unsigned selector) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); + +return pinctrl->functions[selector].name; +} + +static int cygnus_get_function_groups (struct pinctrl_dev *pctrl_dev, +unsigned selector, +const char *const **groups, +unsigned *const num_groups) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); + + *groups = pinctrl->functions[selector].groups; + *num_groups = pinctrl->functions[selector].num_groups; + +return 0 ; +} + +static int cygnus_pinmux_set (struct cygnus_pinctrl *pinctrl, +const struct cygnus_pin_function *func, +const struct cygnus_pin_group *grp, +struct cygnus_mux_log *mux_log) +{ +const struct cygnus_mux *mux = &grp->mux; +int i; +u32 val, mask =0x7 ; +unsigned long flags; + +for (i =0 ; i <CYGNUS_NUM_IOMUX ; i++) { +if (mux->offset != mux_log[i].mux.offset || + mux->shift != mux_log[i].mux.shift) +continue ; + +/* match found if we reach here */ + +/* if this is a new configuration, just do it! */ +if (!mux_log[i].is_configured) +break ; + +/* +* IOMUX has been configured previously and one is trying to +* configure it to a different function +*/ +if (mux_log[i].mux.alt != mux->alt) { +dev_err (pinctrl->dev, +"double configuration error detected!\n" ); +dev_err (pinctrl->dev,"func:%s grp:%s\n" , + func->name, grp->name); +return -EINVAL ; + }else { +/* +* One tries to configure it to the same function. +* Just quit and don't bother +*/ +return 0 ; + } + } + + mux_log[i].mux.alt = mux->alt; + mux_log[i].is_configured = true; + +spin_lock_irqsave (&pinctrl->lock, flags); + + val =readl (pinctrl->base0 + grp->mux.offset); + val &= ~(mask << grp->mux.shift); + val |= grp->mux.alt << grp->mux.shift; +writel (val, pinctrl->base0 + grp->mux.offset); + +spin_unlock_irqrestore (&pinctrl->lock, flags); + +return 0 ; +} + +static int cygnus_pinmux_set_mux (struct pinctrl_dev *pctrl_dev, +unsigned func_select,unsigned grp_select) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); +const struct cygnus_pin_function *func = + &pinctrl->functions[func_select]; +const struct cygnus_pin_group *grp = &pinctrl->groups[grp_select]; + +dev_dbg (pctrl_dev->dev,"func:%u name:%s grp:%u name:%s\n" , + func_select, func->name, grp_select, grp->name); + +dev_dbg (pctrl_dev->dev,"offset:0x%08x shift:%u alt:%u\n" , + grp->mux.offset, grp->mux.shift, grp->mux.alt);
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 914
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +10
-0+ +return cygnus_pinmux_set (pinctrl, func, grp, pinctrl->mux_log); +} + +static int cygnus_gpio_request_enable (struct pinctrl_dev *pctrl_dev, +struct pinctrl_gpio_range *range, +unsigned pin) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); +struct cygnus_gpio_mux *mux = pctrl_dev->desc->pins[pin].drv_data;
const?
Quoted 38 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +38
-0+u32 val; +unsigned long flags; + +/* not all pins support GPIO pinmux override */ +if (!mux->is_supported) +return -ENOTSUPP ; + +spin_lock_irqsave (&pinctrl->lock, flags); + + val =readl (pinctrl->base1 + mux->offset); + val |=0x3 << mux->shift; +writel (val, pinctrl->base1 + mux->offset); + +spin_unlock_irqrestore (&pinctrl->lock, flags); + +dev_dbg (pctrl_dev->dev, +"gpio request enable pin=%u offset=0x%x shift=%u\n" , + pin, mux->offset, mux->shift); + +return 0 ; +} + +static void cygnus_gpio_disable_free (struct pinctrl_dev *pctrl_dev, +struct pinctrl_gpio_range *range, +unsigned pin) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); +struct cygnus_gpio_mux *mux = pctrl_dev->desc->pins[pin].drv_data; +u32 val; +unsigned long flags; + +if (!mux->is_supported) +return ; + +spin_lock_irqsave (&pinctrl->lock, flags); + + val =readl (pinctrl->base1 + mux->offset); + val &= ~(0x3 << mux->shift);
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 962
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +10
-0+writel (val, pinctrl->base1 + mux->offset); + +spin_unlock_irqrestore (&pinctrl->lock, flags); + +dev_err (pctrl_dev->dev, +"gpio disable free pin=%u offset=0x%x shift=%u\n" , + pin, mux->offset, mux->shift); +} + +static struct pinmux_ops cygnus_pinmux_ops = {
const?
Quoted 104 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +104
-0+ .get_functions_count = cygnus_get_functions_count, + .get_function_name = cygnus_get_function_name, + .get_function_groups = cygnus_get_function_groups, + .set_mux = cygnus_pinmux_set_mux, + .gpio_request_enable = cygnus_gpio_request_enable, + .gpio_disable_free = cygnus_gpio_disable_free, +}; + +static struct pinctrl_desc cygnus_pinctrl_desc = { + .name ="cygnus-pinmux" , + .pctlops = &cygnus_pinctrl_ops, + .pmxops = &cygnus_pinmux_ops, +}; + +static int cygnus_mux_log_init (struct cygnus_pinctrl *pinctrl) +{ +struct cygnus_mux_log *log; +unsigned int i, j; + + pinctrl->mux_log =devm_kcalloc (pinctrl->dev,CYGNUS_NUM_IOMUX , +sizeof (struct cygnus_mux_log ), +GFP_KERNEL ); +if (!pinctrl->mux_log) +return -ENOMEM ; + + log = pinctrl->mux_log; +for (i =0 ; i <CYGNUS_NUM_IOMUX_REGS ; i++) { +for (j =0 ; j <CYGNUS_NUM_MUX_PER_REG ; j++) { + log = &pinctrl->mux_log[i *CYGNUS_NUM_MUX_PER_REG + + j]; + log->mux.offset = i *4 ; + log->mux.shift = j *4 ; + log->mux.alt =0 ; + log->is_configured = false; + } + } + +return 0 ; +} + +static int cygnus_pinmux_probe (struct platform_device *pdev) +{ +struct cygnus_pinctrl *pinctrl; +struct resource *res; +int i, ret; +struct pinctrl_pin_desc *pins; +unsigned num_pins =ARRAY_SIZE (cygnus_pins); + + pinctrl =devm_kzalloc (&pdev->dev,sizeof (*pinctrl),GFP_KERNEL ); +if (!pinctrl) +return -ENOMEM ; + + pinctrl->dev = &pdev->dev; +platform_set_drvdata (pdev, pinctrl); +spin_lock_init (&pinctrl->lock); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + pinctrl->base0 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (pinctrl->base0)) { +dev_err (&pdev->dev,"unable to map I/O space\n" ); +return PTR_ERR (pinctrl->base0); + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); + pinctrl->base1 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (pinctrl->base1)) { +dev_err (&pdev->dev,"unable to map I/O space\n" ); +return PTR_ERR (pinctrl->base1); + } + + ret =cygnus_mux_log_init (pinctrl); +if (ret) { +dev_err (&pdev->dev,"unable to initialize IOMUX log\n" ); +return ret; + } + + pins =devm_kcalloc (&pdev->dev, num_pins,sizeof (*pins),GFP_KERNEL ); +if (!pins) +return -ENOMEM ; + +for (i =0 ; i < num_pins; i++) { + pins[i].number = cygnus_pins[i].pin; + pins[i].name = cygnus_pins[i].name; + pins[i].drv_data = &cygnus_pins[i].gpio_mux; + } + + pinctrl->groups = cygnus_pin_groups; + pinctrl->num_groups =ARRAY_SIZE (cygnus_pin_groups); + pinctrl->functions = cygnus_pin_functions; + pinctrl->num_functions =ARRAY_SIZE (cygnus_pin_functions); + cygnus_pinctrl_desc.pins = pins; + cygnus_pinctrl_desc.npins = num_pins; + + pinctrl->pctl =pinctrl_register (&cygnus_pinctrl_desc, &pdev->dev, + pinctrl); +if (!pinctrl->pctl) { +dev_err (&pdev->dev,"unable to register Cygnus IOMUX pinctrl\n" ); +return -EINVAL ; + } + +return 0 ; +} + +static struct of_device_id cygnus_pinmux_of_match[] = {
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 1076
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +10
-0+ { .compatible = "brcm,cygnus-pinmux" }, + { } +}; + +static struct platform_driver cygnus_pinmux_driver = { + .driver = { + .name ="cygnus-pinmux" , + .of_match_table = cygnus_pinmux_of_match, + }, + .probe = cygnus_pinmux_probe,
You also need to either provide remove() method or disallow unbinding via sysfs by setting suppress_bind_attrs in platform driver.
Quoted 14 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +11
-0+}; + +static int __init cygnus_pinmux_init (void ) +{ +return platform_driver_register (&cygnus_pinmux_driver); +} +arch_initcall (cygnus_pinmux_init); + +MODULE_AUTHOR ("Ray Jui <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom Cygnus IOMUX driver" ); +MODULE_LICENSE ("GPL v2" );Signature · 1 line
1.7.9.5
Thanks.
Signature · 1 line
Dmitry
Ray Jui
maintainerRe: [PATCH v3 3/4] pinctrl: cygnus: add initial IOMUX driver support
Quoted 128 lines · Dmitry Torokhov
Hi Ray,
Quoted 6 lines · Ray Jui
This adds the initial driver support for the Broadcom Cygnus IOMUX controller. The Cygnus IOMUX controller supports group based mux configuration but allows certain pins to be muxed to GPIO individually
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Just a few random nits/comments...
Quoted 116 lines
--- drivers/pinctrl/bcm/Kconfig | 13 + drivers/pinctrl/bcm/Makefile | 5 +- drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 1087 ++++++++++++++++++++++++++++++ 3 files changed, 1103 insertions(+), 2 deletions(-) create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-mux.cdrivers/pinctrl/bcm/Kconfig +13
-0@@ -19,3 +19,16 @@ config PINCTRL_BCM2835 bool select PINMUX select PINCONF + +config PINCTRL_CYGNUS_MUX + bool "Broadcom Cygnus IOMUX driver" + depends on (ARCH_BCM_CYGNUS || COMPILE_TEST) + select PINMUX + select GENERIC_PINCONF + default ARCH_BCM_CYGNUS + help + Say yes here to enable the Broadcom Cygnus IOMUX driver. + + The Broadcom Cygnus IOMUX driver supports group based IOMUX + configuration, with the exception that certain individual pins + can be overrided to GPIO functiondrivers/pinctrl/bcm/Makefile +3
-2@@ -1,4 +1,5 @@ # Broadcom pinctrl support -obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o -obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o +obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.odrivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +70
-0@@ -0,0 +1,1087 @@ +/* Copyright (C) 2014-2015 Broadcom Corporation +* +* 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 version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This file contains the Cygnus IOMUX driver that supports group based PINMUX +* configuration. Although PINMUX configuration is mainly group based, the +* Cygnus IOMUX controller allows certain pins to be individually muxed to GPIO +* function, and therefore be controlled by the Cygnus ASIU GPIO controller +*/ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include "../core.h" +#include "../pinctrl-utils.h" + +#define CYGNUS_NUM_IOMUX_REGS 8 +#define CYGNUS_NUM_MUX_PER_REG 8 +#define CYGNUS_NUM_IOMUX (CYGNUS_NUM_IOMUX_REGS * \ + CYGNUS_NUM_MUX_PER_REG) + +/* +* Cygnus IOMUX register description +* +* @offset: register offset for mux configuration of a group +* @shift: bit shift for mux configuration of a group +* @alt: alternate function to set to +*/ +struct cygnus_mux { +unsigned int offset; +unsigned int shift; +unsigned int alt; +}; + +/* +* Keep track of Cygnus IOMUX configuration and prevent double configuration +* +* @cygnus_mux: Cygnus IOMUX register description +* @is_configured: flag to indicate whether a mux setting has already been +* configured +*/ +struct cygnus_mux_log { +struct cygnus_mux mux; +bool is_configured; +}; + +/* +* Group based IOMUX configuration +* +* @name: name of the group +* @pins: array of pins used by this group +* @num_pins: total number of pins used by this group +* @mux: Cygnus group based IOMUX configuration +*/ +struct cygnus_pin_group { +const char *name;
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 73
Quoted 3 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +3
-0+const unsigned *pins; +const unsigned num_pins; +const struct cygnus_mux mux;Not: the last 2 consts are quite weird - if you want to make an instance of
cygnus_pin_groupimmutable you declare it as a const (and I see you are already doing that below). With the structure as it laid out currently you can only do static initializers.
Right. I'll remove the last two const.
Quoted 16 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 86
Quoted 13 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +13
-0+}; + +/* +* Cygnus mux function and supported pin groups +* +* @name: name of the function +* @groups: array of groups that can be supported by this function +* @num_groups: total number of groups that can be supported by this function +*/ +struct cygnus_pin_function { +const char *name; +const char *const *groups; +const unsigned num_groups;Here as well.
Quoted 2 lines
...
Yes. Will remove the last const.
Quoted 8 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 160
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +5
-0+ +/* +* List of pins in Cygnus +*/ +static struct cygnus_pin cygnus_pins[] = {const?
I cannot make it const here, since the address of "gpio_mux" is later passed to pinctrl_pin_desc's private data:
pins[i].drv_data = &cygnus_pins[i].gpio_mux;
Quoted 5 lines
Quoted 2 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +2
-0+CYGNUS_PIN_DESC (0 ,"ext_device_reset_n" ,0 ,0 ,0 ), + CYGNUS_PIN_DESC(1, "chip_mode0", 0, 0, 0),...
Quoted 8 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 482
Quoted 3 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +3
-0+#define CYGNUS_PIN_GROUP (group_name, off, sh, al) \ +{ \ + .name = #group_name"""_grp", \Why do we need extra pair of quotes? BTW we can also do
.name = __stringify(group_name) "_grp",
Okay. I will change to use __stringify. Thanks.
Quoted 11 lines
Quoted 8 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +8
-0+ .pins = group_name ## _pins, \ + .num_pins = ARRAY_SIZE(group_name ## _pins), \ + .mux = { \ + .offset = off, \ + .shift = sh, \ + .alt = al, \ + } \ +}...
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 800
Quoted 2 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +2
-0+ +static struct pinctrl_ops cygnus_pinctrl_ops = {const?
Yes.
Quoted 108 lines
Quoted 108 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +108
-0+ .get_groups_count = cygnus_get_groups_count, + .get_group_name = cygnus_get_group_name, + .get_group_pins = cygnus_get_group_pins, + .pin_dbg_show = cygnus_pin_dbg_show, + .dt_node_to_map = cygnus_dt_node_to_map, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int cygnus_get_functions_count (struct pinctrl_dev *pctrl_dev) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); + +return pinctrl->num_functions; +} + +static const char *cygnus_get_function_name (struct pinctrl_dev *pctrl_dev, +unsigned selector) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); + +return pinctrl->functions[selector].name; +} + +static int cygnus_get_function_groups (struct pinctrl_dev *pctrl_dev, +unsigned selector, +const char *const **groups, +unsigned *const num_groups) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); + + *groups = pinctrl->functions[selector].groups; + *num_groups = pinctrl->functions[selector].num_groups; + +return 0 ; +} + +static int cygnus_pinmux_set (struct cygnus_pinctrl *pinctrl, +const struct cygnus_pin_function *func, +const struct cygnus_pin_group *grp, +struct cygnus_mux_log *mux_log) +{ +const struct cygnus_mux *mux = &grp->mux; +int i; +u32 val, mask =0x7 ; +unsigned long flags; + +for (i =0 ; i <CYGNUS_NUM_IOMUX ; i++) { +if (mux->offset != mux_log[i].mux.offset || + mux->shift != mux_log[i].mux.shift) +continue ; + +/* match found if we reach here */ + +/* if this is a new configuration, just do it! */ +if (!mux_log[i].is_configured) +break ; + +/* +* IOMUX has been configured previously and one is trying to +* configure it to a different function +*/ +if (mux_log[i].mux.alt != mux->alt) { +dev_err (pinctrl->dev, +"double configuration error detected!\n" ); +dev_err (pinctrl->dev,"func:%s grp:%s\n" , + func->name, grp->name); +return -EINVAL ; + }else { +/* +* One tries to configure it to the same function. +* Just quit and don't bother +*/ +return 0 ; + } + } + + mux_log[i].mux.alt = mux->alt; + mux_log[i].is_configured = true; + +spin_lock_irqsave (&pinctrl->lock, flags); + + val =readl (pinctrl->base0 + grp->mux.offset); + val &= ~(mask << grp->mux.shift); + val |= grp->mux.alt << grp->mux.shift; +writel (val, pinctrl->base0 + grp->mux.offset); + +spin_unlock_irqrestore (&pinctrl->lock, flags); + +return 0 ; +} + +static int cygnus_pinmux_set_mux (struct pinctrl_dev *pctrl_dev, +unsigned func_select,unsigned grp_select) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); +const struct cygnus_pin_function *func = + &pinctrl->functions[func_select]; +const struct cygnus_pin_group *grp = &pinctrl->groups[grp_select]; + +dev_dbg (pctrl_dev->dev,"func:%u name:%s grp:%u name:%s\n" , + func_select, func->name, grp_select, grp->name); + +dev_dbg (pctrl_dev->dev,"offset:0x%08x shift:%u alt:%u\n" , + grp->mux.offset, grp->mux.shift, grp->mux.alt); + +return cygnus_pinmux_set (pinctrl, func, grp, pinctrl->mux_log); +} +
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 914
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +6
-0+static int cygnus_gpio_request_enable (struct pinctrl_dev *pctrl_dev, +struct pinctrl_gpio_range *range, +unsigned pin) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); +struct cygnus_gpio_mux *mux = pctrl_dev->desc->pins[pin].drv_data;const?
Yes.
Quoted 42 lines
Quoted 42 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +42
-0+u32 val; +unsigned long flags; + +/* not all pins support GPIO pinmux override */ +if (!mux->is_supported) +return -ENOTSUPP ; + +spin_lock_irqsave (&pinctrl->lock, flags); + + val =readl (pinctrl->base1 + mux->offset); + val |=0x3 << mux->shift; +writel (val, pinctrl->base1 + mux->offset); + +spin_unlock_irqrestore (&pinctrl->lock, flags); + +dev_dbg (pctrl_dev->dev, +"gpio request enable pin=%u offset=0x%x shift=%u\n" , + pin, mux->offset, mux->shift); + +return 0 ; +} + +static void cygnus_gpio_disable_free (struct pinctrl_dev *pctrl_dev, +struct pinctrl_gpio_range *range, +unsigned pin) +{ +struct cygnus_pinctrl *pinctrl =pinctrl_dev_get_drvdata (pctrl_dev); +struct cygnus_gpio_mux *mux = pctrl_dev->desc->pins[pin].drv_data; +u32 val; +unsigned long flags; + +if (!mux->is_supported) +return ; + +spin_lock_irqsave (&pinctrl->lock, flags); + + val =readl (pinctrl->base1 + mux->offset); + val &= ~(0x3 << mux->shift); +writel (val, pinctrl->base1 + mux->offset); + +spin_unlock_irqrestore (&pinctrl->lock, flags); +
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 962
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +6
-0+dev_err (pctrl_dev->dev, +"gpio disable free pin=%u offset=0x%x shift=%u\n" , + pin, mux->offset, mux->shift); +} + +static struct pinmux_ops cygnus_pinmux_ops = {const?
Yes.
Quoted 109 lines
Quoted 109 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +109
-0+ .get_functions_count = cygnus_get_functions_count, + .get_function_name = cygnus_get_function_name, + .get_function_groups = cygnus_get_function_groups, + .set_mux = cygnus_pinmux_set_mux, + .gpio_request_enable = cygnus_gpio_request_enable, + .gpio_disable_free = cygnus_gpio_disable_free, +}; + +static struct pinctrl_desc cygnus_pinctrl_desc = { + .name ="cygnus-pinmux" , + .pctlops = &cygnus_pinctrl_ops, + .pmxops = &cygnus_pinmux_ops, +}; + +static int cygnus_mux_log_init (struct cygnus_pinctrl *pinctrl) +{ +struct cygnus_mux_log *log; +unsigned int i, j; + + pinctrl->mux_log =devm_kcalloc (pinctrl->dev,CYGNUS_NUM_IOMUX , +sizeof (struct cygnus_mux_log ), +GFP_KERNEL ); +if (!pinctrl->mux_log) +return -ENOMEM ; + + log = pinctrl->mux_log; +for (i =0 ; i <CYGNUS_NUM_IOMUX_REGS ; i++) { +for (j =0 ; j <CYGNUS_NUM_MUX_PER_REG ; j++) { + log = &pinctrl->mux_log[i *CYGNUS_NUM_MUX_PER_REG + + j]; + log->mux.offset = i *4 ; + log->mux.shift = j *4 ; + log->mux.alt =0 ; + log->is_configured = false; + } + } + +return 0 ; +} + +static int cygnus_pinmux_probe (struct platform_device *pdev) +{ +struct cygnus_pinctrl *pinctrl; +struct resource *res; +int i, ret; +struct pinctrl_pin_desc *pins; +unsigned num_pins =ARRAY_SIZE (cygnus_pins); + + pinctrl =devm_kzalloc (&pdev->dev,sizeof (*pinctrl),GFP_KERNEL ); +if (!pinctrl) +return -ENOMEM ; + + pinctrl->dev = &pdev->dev; +platform_set_drvdata (pdev, pinctrl); +spin_lock_init (&pinctrl->lock); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + pinctrl->base0 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (pinctrl->base0)) { +dev_err (&pdev->dev,"unable to map I/O space\n" ); +return PTR_ERR (pinctrl->base0); + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); + pinctrl->base1 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (pinctrl->base1)) { +dev_err (&pdev->dev,"unable to map I/O space\n" ); +return PTR_ERR (pinctrl->base1); + } + + ret =cygnus_mux_log_init (pinctrl); +if (ret) { +dev_err (&pdev->dev,"unable to initialize IOMUX log\n" ); +return ret; + } + + pins =devm_kcalloc (&pdev->dev, num_pins,sizeof (*pins),GFP_KERNEL ); +if (!pins) +return -ENOMEM ; + +for (i =0 ; i < num_pins; i++) { + pins[i].number = cygnus_pins[i].pin; + pins[i].name = cygnus_pins[i].name; + pins[i].drv_data = &cygnus_pins[i].gpio_mux; + } + + pinctrl->groups = cygnus_pin_groups; + pinctrl->num_groups =ARRAY_SIZE (cygnus_pin_groups); + pinctrl->functions = cygnus_pin_functions; + pinctrl->num_functions =ARRAY_SIZE (cygnus_pin_functions); + cygnus_pinctrl_desc.pins = pins; + cygnus_pinctrl_desc.npins = num_pins; + + pinctrl->pctl =pinctrl_register (&cygnus_pinctrl_desc, &pdev->dev, + pinctrl); +if (!pinctrl->pctl) { +dev_err (&pdev->dev,"unable to register Cygnus IOMUX pinctrl\n" ); +return -EINVAL ; + } + +return 0 ; +} + +static struct of_device_id cygnus_pinmux_of_match[] = { + { .compatible ="brcm,cygnus-pinmux" }, + { } +}; + +static struct platform_driver cygnus_pinmux_driver = {
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 1076
Quoted 5 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +5
-0+ .driver = { + .name = "cygnus-pinmux", + .of_match_table = cygnus_pinmux_of_match, + }, + .probe = cygnus_pinmux_probe,You also need to either provide
remove()method or disallow unbinding via sysfs by settingsuppress_bind_attrsin platform driver.
I do not expect this driver to ever be compiled as module and uninstalled at runtime. I'll add .suppress_bind_attrs = true, thanks!
Quoted 8 lines
Quoted 8 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +8
-0+}; + +static int __init cygnus_pinmux_init (void ) +{ +return platform_driver_register (&cygnus_pinmux_driver); +} +arch_initcall (cygnus_pinmux_init); +
Quoted 9 lines
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +3
-0+MODULE_AUTHOR ("Ray Jui <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom Cygnus IOMUX driver" ); +MODULE_LICENSE ("GPL v2" );Signature · 1 line
1.7.9.5Thanks.
Thanks for the review!
Ray
Re: [PATCH v3 3/4] pinctrl: cygnus: add initial IOMUX driver support
Quoted 10 lines · Ray Jui
Quoted 9 lines · Dmitry Torokhov
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 160
Quoted 5 lines · Ray Jui
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +5
-0+ +/* +* List of pins in Cygnus +*/ +static struct cygnus_pin cygnus_pins[] = {const?
Quoted 4 lines
I cannot make it const here, since the address of "
gpio_mux" is later passed to pinctrl_pin_desc's private data:pins[i].drv_data = &cygnus_pins[i].gpio_mux;
The pinctrl code says:
"@drv_data: driver-defined per-pin data. pinctrl core does not touch this"
so we could theoretically cast away the constness and restore it when we access drv_data in pin control methods, but I won't insist. I am not sure which way looks nicer.
Thanks.
Signature · 1 line
Dmitry
Ray Jui
maintainerRe: [PATCH v3 3/4] pinctrl: cygnus: add initial IOMUX driver support
Quoted 18 lines · Dmitry Torokhov
Quoted 10 lines · Ray Jui
Quoted 9 lines · Dmitry Torokhov
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c line 160
Quoted 5 lines · Ray Jui
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +5
-0+ +/* +* List of pins in Cygnus +*/ +static struct cygnus_pin cygnus_pins[] = {const?
Quoted 4 lines
I cannot make it const here, since the address of "
gpio_mux" is later passed to pinctrl_pin_desc's private data:pins[i].drv_data = &cygnus_pins[i].gpio_mux;
The pinctrl code says:
Quoted 9 lines
"@drv_data: driver-defined per-pin data. pinctrl core does not touch this"
so we could theoretically cast away the constness and restore it when we access
drv_datain pin control methods, but I won't insist. I am not sure which way looks nicer.Thanks.
Yeah, I agreed that by declaring the cygnus_pins array const, it makes it more obvious that "we do not expect any of its parameters to change." But later if we cast &gpio_mux to void * before assigned to drv_data of pinctrl_pin_desc, we sort of break it up...I'll keep this part of code as it is for now.
Thanks,
Ray
Ray Jui
maintainerPATCH v3 4/4 ARM: dts: enable IOMUX for Broadcom Cygnus
In reply to Ray JuiThis enables the IOMUX support for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 6 ++++++ 1 file changed, 6 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +6 -0
@@ -54,6 +54,12 @@ /include/ "bcm-cygnus-clock.dtsi" + pinctrl: pinctrl@0x0301d0c8 { + compatible = "brcm,cygnus-pinmux"; + reg = <0x0301d0c8 0x30>, + <0x0301d24c 0x2c>; + }; + amba { #address-cells = <1>; #size-cells = <1>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv4 cover Add common clock support for Broadcom iProc architecture
In reply to a message not in the archiveThis patchset contains the initial common clock support for Broadcom's iProc family of SoCs. The iProc clock architecture comprises of various PLLs, e.g., ARMPLL, GENPLL, LCPLL0, MIPIPLL, and etc. An onboard crystal serves as the basic reference clock for these PLLs. Each PLL may have several leaf clocks. One special group of clocks is the ASIU clocks, which are dervied directly from the crystal reference clock.
This patchset also contains the basic clock support for the Broadcom Cygnus SoC, which implements the iProc clock architecture
Changes from v3:
- Fix incorrect use of passing in of_clk_src_onecell_get when adding ARM PLL and other iProc PLLs as clock provider. These PLLs have zero cells in DT and thefore of_clk_src_simple_get should be used instead
- Rename Cygnus MIPI PLL Channel 2 clock from BCM_CYGNUS_MIPIPLL_CH2_UNUSED to BCM_CYGNUS_MIPIPLL_CH2_V3D, since a 3D graphic rendering engine has been integrated into Cygnus revision B0 and has its core clock running off MIPI PLL Channel 2
- Changed default MIPI PLL VCO frequency from 1.75 GHz to 2.1 GHz. This allows us to derive 300 MHz V3D clock from channel 2 through the post divisor
Changes from v2:
- Re-arrange Cygnus clock/pll init functions so each init function is right next to its clock table
- Removed #defines for number of clocks in Cygnus. Have the number of clocks automatically determined based on array size of the clock table
Changes from v1:
- Separate drivers/clk/Makefile change for drivers/clk/bcm out to a standalone patch
Ray Jui (5):
clk: iproc: define Broadcom iProc clock binding
clk: iproc: add initial common clock support
clk: Change bcm clocks build dependency
clk: cygnus: add clock support for Broadcom Cygnus
ARM: dts: enable clock support for Broadcom Cygnus
arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 +++++-- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- brcm,iproc-clocks.txt | 178 ++++++++++++ drivers/clk/Makefile | 2 +- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 2 + drivers/clk/bcm/clk-cygnus.c | 277 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-armpll.c | 282 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 +++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 478 +++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 155 ++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 65 +++++ 13 files changed, 2046 insertions(+), 27 deletions(-) create mode 100644 brcm,iproc-clocks.txt create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 1/5 clk: iproc: define Broadcom iProc clock binding
Document the device tree binding for Broadcom iProc architecture based clock controller
--- brcm,iproc-clocks.txt | 178 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 brcm,iproc-clocks.txt
brcm,iproc-clocks.txt new file +178 -0
@@ -0,0 +1,178 @@ +Broadcom iProc Family Clocks + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +The iProc clock controller manages clocks that are common to the iProc family. +An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL, +LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL +comprises of several leaf clocks + +Required properties for PLLs: +- compatible: + Should have a value of the form "brcm,<soc>-<pll>". For example, GENPLL on +Cygnus has a compatible string of "brcm,cygnus-genpll" + +- #clock-cells: + Must be <0> + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL + +- clocks: + The input parent clock phandle for the PLL. For all iProc PLLs, this is an +onboard crystal with a fixed rate + +Optional Properties for PLLs: +- clock-frequency: + PLL frequency in Hz. If specified, PLL will be configured to run at +<clock-frequency> instead of the default frequency after chip reset, provided +that <clock-frequency> and its parameters are defined in the SoC specific +frequency parameter table + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + +Required properties for leaf clocks of a PLL: + +- compatible: + Should have a value of the form "brcm,<soc>-<pll>-clk". For example, leaf +clocks derived from the GENPLL on Cygnus SoC have a compatible string of +"brcm,cygnus-genpll-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 leaf clock of a +given PLL + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL leaf clocks + +- clocks: + The input parent PLL phandle for the leaf clock + +- clock-output-names: + An ordered list of strings defining the names of the leaf clocks + +Example: + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + +Required properties for ASIU clocks: + +ASIU clocks are a special case. These clocks are derived directly from the +reference clock of the onboard crystal + +- compatible: + Should have a value of the form "brcm,<soc>-asiu-clk". For example, ASIU +clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 ASIU clocks + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for ASIU clocks + +- clocks: + The input parent clock phandle for the ASIU clock, i.e., the onboard +crystal + +- clock-output-names: + An ordered list of strings defining the names of the ASIU clocks + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; + }; + +Cygnus +------ +PLL and leaf clock compatible strings for Cygnus are: + "brcm,cygnus-armpll" + "brcm,cygnus-genpll" + "brcm,cygnus-lcpll0" + "brcm,cygnus-mipipll" + "brcm,cygnus-genpll-clk" + "brcm,cygnus-lcpll0-clk" + "brcm,cygnus-mipipll-clk" + "brcm,cygnus-asiu-clk" + +The following table defines the set of PLL/clock index and ID for Cygnus. +These clock IDs are defined in: + "include/dt-bindings/clock/bcm-cygnus.h" + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + armpll crystal N/A N/A + genpll crystal N/A N/A + lcpll0 crystal N/A N/A + mipipll crystal N/A N/A + + keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK + adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK + pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK + + axi21 genpll 0 BCM_CYGNUS_GENPLL_AXI21_CLK + 250mhz genpll 1 BCM_CYGNUS_GENPLL_250MHZ_CLK + ihost_sys genpll 2 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK + enet_sw genpll 3 BCM_CYGNUS_GENPLL_ENET_SW_CLK + audio_125 genpll 4 BCM_CYGNUS_GENPLL_AUDIO_125_CLK + can genpll 5 BCM_CYGNUS_GENPLL_CAN_CLK + + pcie_phy lcpll0 0 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK + ddr_phy lcpll0 1 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK + sdio lcpll0 2 BCM_CYGNUS_LCPLL0_SDIO_CLK + usb_phy lcpll0 3 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK + smart_card lcpll0 4 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK + ch5 lcpll0 5 BCM_CYGNUS_LCPLL0_CH5_UNUSED + + ch0_unused mipipll 0 BCM_CYGNUS_MIPIPLL_CH0_UNUSED + ch1_lcd mipipll 1 BCM_CYGNUS_MIPIPLL_CH1_LCD + ch2_unused mipipll 2 BCM_CYGNUS_MIPIPLL_CH2_UNUSED + ch3_unused mipipll 3 BCM_CYGNUS_MIPIPLL_CH3_UNUSED + ch4_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH4_UNUSED + ch5_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH5_UNUSED
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 2/5 clk: iproc: add initial common clock support
In reply to Ray JuiThis adds basic and generic support for various iProc PLLs and clocks including the ARMPLL, GENPLL, LCPLL, MIPIPLL, and ASIU clocks.
SoCs under the iProc architecture can define their specific register offsets and clock parameters for their PLL and clock controllers. These parameters can be passed as arugments into the generic iProc PLL and clock setup functions
Derived from code originally provided by Jonathan Richardson <[email protected]>
--- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-iproc-armpll.c | 282 +++++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 +++++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 478 ++++++++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 155 ++++++++++++ 7 files changed, 1438 insertions(+) create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h
drivers/clk/bcm/Kconfig +9 -0
@@ -7,3 +7,12 @@ config CLK_BCM_KONA Enable common clock framework support for Broadcom SoCs using "Kona" style clock control units, including those in the BCM281xx and BCM21664 families. + +config COMMON_CLK_IPROC + bool "Broadcom iProc clock support" + depends on ARCH_BCM_IPROC + depends on COMMON_CLK + default y + help + Enable common clock framework support for Broadcom SoCs + based on the "iProc" architecture
drivers/clk/bcm/Makefile +1 -0
@@ -2,3 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o +obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o
drivers/clk/bcm/clk-iproc-armpll.c new file +282 -0
282 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-asiu.c new file +275 -0
275 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-clk.c new file +238 -0
238 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-pll.c new file +478 -0
478 lines not on this page · raw message
drivers/clk/bcm/clk-iproc.h new file +155 -0
155 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v4 2/5] clk: iproc: add initial common clock support
Quoted 7 lines · Ray Jui
drivers/clk/bcm/clk-iproc-pll.c new file +7
-0+/* +* Get the clock rate based on name +*/ +static unsigned long __get_rate (const char *clk_name) +{ +struct clk *clk; +
drivers/clk/bcm/clk-iproc-pll.c line 96
Quoted 10 lines
drivers/clk/bcm/clk-iproc-pll.c new file +10
-0+ clk =__clk_lookup (clk_name); +if (!clk) { +pr_err ("%s: unable to find clock by name: %s\n" , __func__, + clk_name); +return 0 ; + } + +return clk_get_rate (clk); +} +
This looks like something we should be providing in the core framework. Care to make it into an of_clk_get_parent_rate() API?
drivers/clk/bcm/clk-iproc.h line 153
Quoted 10 lines
drivers/clk/bcm/clk-iproc.h new file +10
-0+extern void __init iproc_armpll_setup (struct device_node *node); +extern void __init iproc_pll_setup (struct device_node *node, +const struct iproc_pll_ctrl *ctrl, +const struct iproc_pll_vco_freq_param *vco_param, +unsigned int num_freqs); +extern void __init iproc_clk_setup (struct device_node *node, +const struct iproc_clk_ctrl *ctrl,unsigned int num_clks); +extern void __init iproc_asiu_setup (struct device_node *node, +const struct iproc_asiu_div *div, +const struct iproc_asiu_gate *gate,unsigned int num_clks);
__init is not necessary in header files.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Ray Jui
maintainerRe: [PATCH v4 2/5] clk: iproc: add initial common clock support
Quoted 13 lines · Stephen Boyd
Quoted 12 lines · Ray Jui
drivers/clk/bcm/clk-iproc-pll.c new file +12
-0+/* +* Get the clock rate based on name +*/ +static unsigned long __get_rate (const char *clk_name) +{ +struct clk *clk; + + clk =__clk_lookup (clk_name); +if (!clk) { +pr_err ("%s: unable to find clock by name: %s\n" , __func__, + clk_name); +return 0 ;
Quoted 9 lines
drivers/clk/bcm/clk-iproc-pll.c line 96
Quoted 5 lines
drivers/clk/bcm/clk-iproc-pll.c new file +5
-0+ } + +return clk_get_rate (clk); +} +This looks like something we should be providing in the core framework. Care to make it into an
of_clk_get_parent_rate()API?
I would love to! Note __get_rate here is really getting the clock rate with a name provided. Can you be more specific on what you want? If I'm not mistaken, what you really want is this?
unsigned long of_clk_get_parent_rate(struct device_node *np, int index);
Quoted 4 lines
Quoted 4 lines
drivers/clk/bcm/clk-iproc.h new file +4
-0+extern void __init iproc_armpll_setup (struct device_node *node); +extern void __init iproc_pll_setup(struct device_node *node, + const struct iproc_pll_ctrl *ctrl, + const struct iproc_pll_vco_freq_param *vco_param,
Quoted 9 lines
drivers/clk/bcm/clk-iproc.h line 153
Quoted 6 lines
drivers/clk/bcm/clk-iproc.h new file +6
-0+ unsigned int num_freqs); +extern void __init iproc_clk_setup (struct device_node *node, +const struct iproc_clk_ctrl *ctrl,unsigned int num_clks); +extern void __init iproc_asiu_setup (struct device_node *node, +const struct iproc_asiu_div *div, +const struct iproc_asiu_gate *gate,unsigned int num_clks);
__initis not necessary in header files.
Okay I'll remove __init. Thanks.
Ray
Re: [PATCH v4 2/5] clk: iproc: add initial common clock support
Quoted 23 lines · Ray Jui
Quoted 12 lines · Stephen Boyd
Quoted 11 lines · Ray Jui
drivers/clk/bcm/clk-iproc-pll.c new file +11
-0+/* +* Get the clock rate based on name +*/ +static unsigned long __get_rate (const char *clk_name) +{ +struct clk *clk; + + clk =__clk_lookup (clk_name); +if (!clk) { +pr_err ("%s: unable to find clock by name: %s\n" , __func__, + clk_name);Quoted 9 lines
drivers/clk/bcm/clk-iproc-pll.c line 96
Quoted 6 lines
drivers/clk/bcm/clk-iproc-pll.c new file +6
-0+return 0 ; + } + +return clk_get_rate (clk); +} +This looks like something we should be providing in the core framework. Care to make it into an
of_clk_get_parent_rate()API?
Quoted 5 lines
I would love to! Note
__get_ratehere is really getting the clock rate with a name provided. Can you be more specific on what you want? If I'm not mistaken, what you really want is this?unsigned long
of_clk_get_parent_rate(struct device_node *np, int index);
Yes that looks good.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Ray Jui
maintainerPATCH v4 3/5 clk: Change bcm clocks build dependency
In reply to Ray JuiThe clock code under drivers/clk/bcm now contains code for both the Broadcom mobile SoCs and the iProc SoCs. Change the the makefile dependency to be under config flag CONFIG_ARCH_BCM that's enabled for both families of SoCs
--- drivers/clk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/Makefile +1 -1
@@ -41,7 +41,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ -obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ +obj-$(CONFIG_ARCH_BCM) += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HIP04) += hisilicon/
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 4/5 clk: cygnus: add clock support for Broadcom Cygnus
In reply to Ray JuiThe Broadcom Cygnus SoC is architected under the iProc architecture. It has the following PLLs: ARMPLL, GENPLL, LCPLL0, MIPIPLL, all dervied from an onboard crystal. Cygnus also has various ASIU clocks that are derived directly from the onboard crystal.
--- drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-cygnus.c | 277 ++++++++++++++++++++++++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 65 ++++++++ 3 files changed, 343 insertions(+) create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
drivers/clk/bcm/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o +obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
drivers/clk/bcm/clk-cygnus.c new file +277 -0
277 lines not on this page · raw message
include/dt-bindings/clock/bcm-cygnus.h new file +65 -0
65 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 5/5 ARM: dts: enable clock support for Broadcom Cygnus
In reply to Ray JuiReplace current device tree dummy clocks with real clock support for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 ++++++++++++++++++++++++------- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- 2 files changed, 86 insertions(+), 26 deletions(-)
arch/arm/boot/dts/bcm-cygnus-clock.dtsi +85 -25
@@ -36,56 +36,116 @@ clocks { ranges; osc: oscillator { + #clock-cells = <0>; compatible = "fixed-clock"; - #clock-cells = <1>; clock-frequency = <25000000>; }; - apb_clk: apb_clk { - compatible = "fixed-clock"; + /* Cygnus ARM PLL */ + armpll: armpll { #clock-cells = <0>; - clock-frequency = <1000000000>; + compatible = "brcm,cygnus-armpll"; + clocks = <&osc>; + reg = <0x19000000 0x1000>; }; - periph_clk: periph_clk { - compatible = "fixed-clock"; + /* peripheral clock for system timer */ + arm_periph_clk: arm_periph_clk { #clock-cells = <0>; - clock-frequency = <500000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <2>; + clock-mult = <1>; }; - sdio_clk: lcpll_ch2 { - compatible = "fixed-clock"; + /* APB bus clock */ + apb_clk: apb_clk { #clock-cells = <0>; - clock-frequency = <200000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <4>; + clock-mult = <1>; }; - axi81_clk: axi81_clk { - compatible = "fixed-clock"; + genpll: genpll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - keypad_clk: keypad_clk { - compatible = "fixed-clock"; + /* various clocks running off the GENPLL */ + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + + /* always 1/2 of the axi21 clock */ + axi41_clk: axi41_clk { #clock-cells = <0>; - clock-frequency = <31806>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <2>; + clock-mult = <1>; }; - adc_clk: adc_clk { - compatible = "fixed-clock"; + /* always 1/4 of the axi21 clock */ + axi81_clk: axi81_clk { #clock-cells = <0>; - clock-frequency = <1562500>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <4>; + clock-mult = <1>; }; - pwm_clk: pwm_clk { - compatible = "fixed-clock"; + lcpll0: lcpll0 { #clock-cells = <0>; - clock-frequency = <1000000>; + compatible = "brcm,cygnus-lcpll0"; + reg = <0x0301d02c 0x1c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - lcd_clk: mipipll_ch1 { - compatible = "fixed-clock"; + /* various clocks running off the LCPLL0 */ + lcpll0_clks: lcpll0_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-lcpll0-clk"; + reg = <0x0301d02c 0x1c>; + clocks = <&lcpll0>; + clock-output-names = "pcie_phy", "ddr_phy", "sdio", + "usb_phy", "smart_card", "ch5"; + }; + + mipipll: mipipll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-mipipll"; + reg = <0x180a9800 0x2c>, + <0x0301c020 0x4>, + <0x180aa024 0x4>; + clock-frequency = <2100000000>; + clocks = <&osc>; + }; + + mipipll_clks: mipipll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-mipipll-clk"; + reg = <0x180a9800 0x2c>; + clocks = <&mipipll>; + clock-output-names = "ch0_unused", "ch1_lcd", "ch2_unused", + "ch3_unused", "ch4_unused", "ch5_unused"; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; }; };
arch/arm/boot/dts/bcm-cygnus.dtsi +1 -1
@@ -134,7 +134,7 @@ compatible = "arm,cortex-a9-global-timer"; reg = <0x19020200 0x100>; interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&periph_clk>; + clocks = <&arm_periph_clk>; }; };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv7 cover Add gpio/pinconf support to Broadcom Cygnus SoC
In reply to a message not in the archiveThis 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 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 | 920 ++++++++++++++++++++ 6 files changed, 1091 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 v7 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 v7 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 | 920 +++++++++++++++++++++++++++++ 3 files changed, 943 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 +920 -0
920 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v7 2/4] pinctrl: cygnus: add gpio/pinconf driver
Quoted 153 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]>--- drivers/pinctrl/bcm/Kconfig | 22 + drivers/pinctrl/bcm/Makefile | 1 + drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c | 920 +++++++++++++++++++++++++++++ 3 files changed, 943 insertions(+) create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-gpio.cdrivers/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.odrivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +86
-0@@ -0,0 +1,920 @@ +/* +* Copyright (C) 2014-2015 Broadcom Corporation +* +* 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 version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This file contains the Broadcom Cygnus GPIO driver that supports 3 +* GPIO controllers on Cygnus including the ASIU GPIO controller, the +* chipCommonG GPIO controller, and the always-on GPIO controller. Basic +* PINCONF such as bias pull up/down, and drive strength are also supported +* in this driver. +* +* Pins from the ASIU GPIO can be individually muxed to GPIO function, +* through the interaction with the Cygnus IOMUX controller +*/ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/ioport.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> + +#include "../pinctrl-utils.h" + +#define CYGNUS_GPIO_DATA_IN_OFFSET 0x00 +#define CYGNUS_GPIO_DATA_OUT_OFFSET 0x04 +#define CYGNUS_GPIO_OUT_EN_OFFSET 0x08 +#define CYGNUS_GPIO_IN_TYPE_OFFSET 0x0c +#define CYGNUS_GPIO_INT_DE_OFFSET 0x10 +#define CYGNUS_GPIO_INT_EDGE_OFFSET 0x14 +#define CYGNUS_GPIO_INT_MSK_OFFSET 0x18 +#define CYGNUS_GPIO_INT_STAT_OFFSET 0x1c +#define CYGNUS_GPIO_INT_MSTAT_OFFSET 0x20 +#define CYGNUS_GPIO_INT_CLR_OFFSET 0x24 +#define CYGNUS_GPIO_PAD_RES_OFFSET 0x34 +#define CYGNUS_GPIO_RES_EN_OFFSET 0x38 + +/* drive strength control for ASIU GPIO */ +#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 + +/* drive strength control for CCM/CRMU (AON) GPIO */ +#define CYGNUS_GPIO_DRV0_CTRL_OFFSET 0x00 + +#define GPIO_BANK_SIZE 0x200 +#define NGPIOS_PER_BANK 32 +#define GPIO_BANK (pin) ((pin) / NGPIOS_PER_BANK) + +#define CYGNUS_GPIO_REG (pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg)) +#define CYGNUS_GPIO_SHIFT (pin) ((pin) % NGPIOS_PER_BANK) + +#define GPIO_DRV_STRENGTH_BIT_SHIFT 20 +#define GPIO_DRV_STRENGTH_BITS 3 +#define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1) + +/* +* Cygnus GPIO core +* +* @dev: pointer to device +* @base: I/O register base for Cygnus GPIO controller +* @io_ctrl: I/O register base for certain type of Cygnus GPIO controller that +* has the PINCONF support implemented outside of the GPIO block +* @lock: lock to protect access to I/O registers +* @gc: GPIO chip +* @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs +* @pinmux_is_supported: flag to indicate this GPIO controller contains pins +* that can be individually muxed to GPIO +* @pctl: pointer to pinctrl_dev +* @pctldesc: pinctrl descriptor +* @pins: pointer to array of pins +*/ +struct cygnus_gpio { +struct device *dev;
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 96
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+ +void __iomem *base; +void __iomem *io_ctrl; + +spinlock_t lock; + +struct gpio_chip gc; +unsigned num_banks; + +int pinmux_is_supported;
bool?
Quoted 290 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +290
-0+ +struct pinctrl_dev *pctl; +struct pinctrl_desc pctldesc; +struct pinctrl_pin_desc *pins; +}; + +static struct cygnus_gpio *to_cygnus_gpio (struct gpio_chip *gc) +{ + return container_of(gc, struct cygnus_gpio, gc); +} + +/* +* Mapping from PINCONF pins to GPIO pins is 1-to-1 +*/ +static unsigned cygnus_pin_to_gpio (unsigned pin) +{ +return pin; +} + +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); +} + +/** +* cygnus_set_bit - set or clear one bit (corresponding to the GPIO pin) in a +* Cygnus GPIO register +* +* @cygnus_gpio: Cygnus GPIO device +* @reg: register offset +* @gpio: GPIO pin +* @set: set or clear. 1 - set; 0 -clear +*/ +static void cygnus_set_bit (struct cygnus_gpio *chip,unsigned int reg, +unsigned gpio,int set) +{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + 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) +{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + val =cygnus_readl (chip, offset) &BIT (shift); +if (val) +return 1 ; +else +return 0 ; +} + +static void cygnus_gpio_irq_handler (unsigned int irq,struct irq_desc *desc) +{ +struct gpio_chip *gc =irq_desc_get_handler_data (desc); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +struct irq_chip *irq_chip =irq_desc_get_chip (desc); +int i, bit; + +chained_irq_enter (irq_chip, desc); + +/* go through the entire GPIO banks and handle all interrupts */ +for (i =0 ; i < chip->num_banks; i++) { +unsigned long val =cygnus_readl (chip, + (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_MSTAT_OFFSET ); + +for_each_set_bit (bit, &val,NGPIOS_PER_BANK ) { +unsigned pin =NGPIOS_PER_BANK * i + bit; +int child_irq =irq_find_mapping (gc->irqdomain, pin); + +/* +* Clear the interrupt before invoking the +* handler, so we do not leave any window +*/ +cygnus_writel (chip, (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_CLR_OFFSET ,BIT (bit)); + +generic_handle_irq (child_irq); + } + } + +chained_irq_exit (irq_chip, desc); +} + + +static void cygnus_gpio_irq_ack (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = d->hwirq; +unsigned int offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_INT_CLR_OFFSET ); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val =BIT (shift); + +cygnus_writel (chip, offset, val); +} + +/** +* cygnus_gpio_irq_set_mask - mask/unmask a GPIO interrupt +* +* @d: IRQ chip data +* @mask: mask/unmask GPIO interrupt. 0 - mask (disable); 1 - unmask (enable) +*/ +static void cygnus_gpio_irq_set_mask (struct irq_data *d,int mask) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = d->hwirq; + +cygnus_set_bit (chip,CYGNUS_GPIO_INT_MSK_OFFSET , gpio, mask); +} + +static void cygnus_gpio_irq_mask (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_gpio_irq_set_mask (d,0 ); +spin_unlock_irqrestore (&chip->lock, flags); +} + +static void cygnus_gpio_irq_unmask (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_gpio_irq_set_mask (d,1 ); +spin_unlock_irqrestore (&chip->lock, flags); +} + +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 ; +unsigned long flags; + +switch (type &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_EDGE_RISING : + edge_lvl =1 ; +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 ; +} + +static struct irq_chip cygnus_gpio_irq_chip = { + .name ="bcm-cygnus-gpio" , + .irq_ack = cygnus_gpio_irq_ack, + .irq_mask = cygnus_gpio_irq_mask, + .irq_unmask = cygnus_gpio_irq_unmask, + .irq_set_type = cygnus_gpio_irq_set_type, +}; + +/* +* 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); +} + +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); +} + +static int cygnus_gpio_direction_input (struct gpio_chip *gc,unsigned gpio) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_OUT_EN_OFFSET , gpio,0 ); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set input\n" , gpio); + +return 0 ; +} + +static int cygnus_gpio_direction_output (struct gpio_chip *gc,unsigned gpio, +int value) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_OUT_EN_OFFSET , gpio,1 ); +cygnus_set_bit (chip,CYGNUS_GPIO_DATA_OUT_OFFSET , gpio, value); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set output, value:%d\n" , gpio, value); + +return 0 ; +} + +static void cygnus_gpio_set (struct gpio_chip *gc,unsigned gpio,int value) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_DATA_OUT_OFFSET , gpio, value); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set, value:%d\n" , gpio, value); +} + +static int cygnus_gpio_get (struct gpio_chip *gc,unsigned gpio) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned int offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_DATA_IN_OFFSET ); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); + +return !!(cygnus_readl (chip, offset) &BIT (shift)); +} + +static int cygnus_get_groups_count (struct pinctrl_dev *pctldev) +{ +return 1 ;
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 396
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+} + +/* +* Only one group: "gpio_grp", since this local pinctrl device only performs +* GPIO specific PINCONF configurations +*/ +static const char *cygnus_get_group_name (struct pinctrl_dev *pctldev, +unsigned selector) +{ +
Extra blank line.
Quoted 315 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +315
-0+return "gpio_grp" ; +} + +static const struct pinctrl_ops cygnus_pctrl_ops = { + .get_groups_count = cygnus_get_groups_count, + .get_group_name = cygnus_get_group_name, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int cygnus_gpio_set_pull (struct cygnus_gpio *chip,unsigned gpio, +int disable,int pull_up) +{ +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); + +if (disable) { +cygnus_set_bit (chip,CYGNUS_GPIO_RES_EN_OFFSET , gpio,0 ); + }else { +cygnus_set_bit (chip,CYGNUS_GPIO_PAD_RES_OFFSET , gpio, + pull_up); +cygnus_set_bit (chip,CYGNUS_GPIO_RES_EN_OFFSET , gpio,1 ); + } + +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set pullup:%d\n" , gpio, pull_up); + +return 0 ; +} + +static void cygnus_gpio_get_pull (struct cygnus_gpio *chip,unsigned gpio, +int *disable,int *pull_up) +{ +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); + *disable = !cygnus_get_bit (chip,CYGNUS_GPIO_RES_EN_OFFSET , gpio); + *pull_up =cygnus_get_bit (chip,CYGNUS_GPIO_PAD_RES_OFFSET , gpio); +spin_unlock_irqrestore (&chip->lock, flags); +} + +static int cygnus_gpio_set_strength (struct cygnus_gpio *chip,unsigned gpio, +unsigned strength) +{ +void __iomem *base; +unsigned int i, offset, shift; +u32 val; +unsigned long flags; + +/* make sure drive strength is supported */ +if (strength <2 || strength >16 || (strength %2 )) +return -ENOTSUPP ; + +if (chip->io_ctrl) { + base = chip->io_ctrl; + offset =CYGNUS_GPIO_DRV0_CTRL_OFFSET ; + }else { + base = chip->base; + offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET ); + } + + shift =CYGNUS_GPIO_SHIFT (gpio); + +dev_dbg (chip->dev,"gpio:%u set drive strength:%d mA\n" , gpio, + strength); + +spin_lock_irqsave (&chip->lock, flags); + strength = (strength /2 ) -1 ; +for (i =0 ; i <GPIO_DRV_STRENGTH_BITS ; i++) { + val =readl (base + offset); + val &= ~BIT (shift); + val |= ((strength >> i) &0x1 ) << shift; +writel (val, base + offset); + offset +=4 ; + } +spin_unlock_irqrestore (&chip->lock, flags); + +return 0 ; +} + +static int cygnus_gpio_get_strength (struct cygnus_gpio *chip,unsigned gpio, +u16 *strength) +{ +void __iomem *base; +unsigned int i, offset, shift; +u32 val; +unsigned long flags; + +if (chip->io_ctrl) { + base = chip->io_ctrl; + offset =CYGNUS_GPIO_DRV0_CTRL_OFFSET ; + }else { + base = chip->base; + offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET ); + } + + shift =CYGNUS_GPIO_SHIFT (gpio); + +spin_lock_irqsave (&chip->lock, flags); + *strength =0 ; +for (i =0 ; i <GPIO_DRV_STRENGTH_BITS ; i++) { + val =readl (base + offset) &BIT (shift); + val >>= shift; + *strength += (val << i); + offset +=4 ; + } + +/* convert to mA */ + *strength = (*strength +1 ) *2 ; +spin_unlock_irqrestore (&chip->lock, flags); + +return 0 ; +} + +static int cygnus_pin_config_get (struct pinctrl_dev *pctldev,unsigned pin, +unsigned long *config) +{ +struct cygnus_gpio *chip =pinctrl_dev_get_drvdata (pctldev); +enum pin_config_param param =pinconf_to_config_param (*config); +unsigned gpio =cygnus_pin_to_gpio (pin); +u16 arg; +int disable, pull_up, ret; + +switch (param) { +case PIN_CONFIG_BIAS_DISABLE : +cygnus_gpio_get_pull (chip, gpio, &disable, &pull_up); +if (disable) +return 0 ; +else +return -EINVAL ; + +case PIN_CONFIG_BIAS_PULL_UP : +cygnus_gpio_get_pull (chip, gpio, &disable, &pull_up); +if (!disable && pull_up) +return 0 ; +else +return -EINVAL ; + +case PIN_CONFIG_BIAS_PULL_DOWN : +cygnus_gpio_get_pull (chip, gpio, &disable, &pull_up); +if (!disable && !pull_up) +return 0 ; +else +return -EINVAL ; + +case PIN_CONFIG_DRIVE_STRENGTH : + ret =cygnus_gpio_get_strength (chip, gpio, &arg); +if (ret) +return ret; +else + *config =pinconf_to_config_packed (param, arg); + +return 0 ; + +default : +return -ENOTSUPP ; + } + +return -ENOTSUPP ; +} + +static int cygnus_pin_config_set (struct pinctrl_dev *pctldev,unsigned pin, +unsigned long *configs,unsigned num_configs) +{ +struct cygnus_gpio *chip =pinctrl_dev_get_drvdata (pctldev); +enum pin_config_param param; +u16 arg; +unsigned i, gpio =cygnus_pin_to_gpio (pin); +int ret = -ENOTSUPP ; + +for (i =0 ; i < num_configs; i++) { + param =pinconf_to_config_param (configs[i]); + arg =pinconf_to_config_argument (configs[i]); + +switch (param) { +case PIN_CONFIG_BIAS_DISABLE : + ret =cygnus_gpio_set_pull (chip, gpio,1 ,0 ); +if (ret <0 ) + goto out; +break ; + +case PIN_CONFIG_BIAS_PULL_UP : + ret =cygnus_gpio_set_pull (chip, gpio,0 ,1 ); +if (ret <0 ) + goto out; +break ; + +case PIN_CONFIG_BIAS_PULL_DOWN : + ret =cygnus_gpio_set_pull (chip, gpio,0 ,0 ); +if (ret <0 ) + goto out; +break ; + +case PIN_CONFIG_DRIVE_STRENGTH : + ret =cygnus_gpio_set_strength (chip, gpio, arg); +if (ret <0 ) + goto out; +break ; + +default : +dev_err (chip->dev,"invalid configuration\n" ); +return -ENOTSUPP ; + } + }/* for each config */ + +out: +return ret; +} + +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, +}; + +/* +* 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 } + +/* +* 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; + +/* 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); +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 */ +for (i =0 ; i <ARRAY_SIZE (cygnus_gpio_pintable); i++) { + ret = gpiochip_add_pin_range(gc, dev_name(&pinmux_pdev->dev),
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 721
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+ 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_rm_pin_range; + } + } + + chip->pinmux_is_supported =1 ;
chip->pinmux_is_supported = true;
?
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 725
Quoted 4 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +4
-0+return 0 ; + +err_rm_pin_range: +gpiochip_remove_pin_ranges (gc);
I think you need:
put_dveice(&pinmux_pdev->dev);
since of_find_device_by_node calls bus_find_device() that takes reference to found device.
... And now that I look at this majority of users of of_find_device_by_node() is broken like that :(
BTW, it looks like you only need pinmux_dev for it's name so you probably need to drop reference in success path as well.
Quoted 23 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +23
-0+return ret; +} + +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); +} + +/* +* Cygnus GPIO controller supports some PINCONF related configurations such as +* pull up, pull down, and drive strength, when the pin is configured to GPIO +* +* Here a local pinctrl device is created with simple 1-to-1 pin mapping to the +* local GPIO pins +*/ +static int cygnus_gpio_register_pinconf (struct cygnus_gpio *chip) +{ +struct pinctrl_desc *pctldesc = &chip->pctldesc; +struct pinctrl_pin_desc *pins; +struct gpio_chip *gc = &chip->gc;
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 758
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+int i, ret; + + pins =devm_kcalloc (chip->dev, gc->ngpio,sizeof (*pins),GFP_KERNEL ); +if (!pins) +return -ENOMEM ; + chip->pins = pins; + +for (i =0 ; i < gc->ngpio; i++) { + pins[i].number = i; + pins[i].name =kasprintf (GFP_KERNEL ,"gpio-%d" , i);
We have devm_kasprintf().
Quoted 28 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +28
-0+if (!pins[i].name) { + ret = -ENOMEM ; + goto err_kfree; + } + } + + pctldesc->name =dev_name (chip->dev); + pctldesc->pctlops = &cygnus_pctrl_ops; + pctldesc->pins = pins; + pctldesc->npins = gc->ngpio; + pctldesc->confops = &cygnus_pconf_ops; + + chip->pctl =pinctrl_register (pctldesc, chip->dev, chip); +if (!chip->pctl) { +dev_err (chip->dev,"unable to register pinctrl device\n" ); + ret = -EINVAL ; + goto err_kfree; + } + +return 0 ; + +err_kfree: +for (i =0 ; i < gc->ngpio; i++) +kfree (pins[i].name); + +return ret; +} +
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 796
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+static void cygnus_gpio_unregister_pinconf (struct cygnus_gpio *chip) +{ +struct gpio_chip *gc = &chip->gc; +int i; + +if (chip->pctl) +pinctrl_unregister (chip->pctl); + +for (i =0 ; i < gc->ngpio; i++) +kfree (chip->pins[i].name);
Should not be needed if you use devm_kasprintf.
Quoted 103 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +103
-0+} + +static const struct of_device_id cygnus_gpio_of_match[] = { + { .compatible ="brcm,cygnus-gpio" }, + { } +}; +MODULE_DEVICE_TABLE (of, cygnus_gpio_of_match); + +static int cygnus_gpio_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct resource *res; +struct cygnus_gpio *chip; +struct gpio_chip *gc; +u32 ngpios; +int irq, ret; + + chip =devm_kzalloc (dev,sizeof (*chip),GFP_KERNEL ); +if (!chip) +return -ENOMEM ; + + chip->dev = dev; +platform_set_drvdata (pdev, chip); + +if (of_property_read_u32 (dev->of_node,"ngpios" , &ngpios)) { +dev_err (dev,"missing ngpios DT property\n" ); +return -ENODEV ; + } + chip->num_banks = (ngpios +NGPIOS_PER_BANK -1 ) /NGPIOS_PER_BANK ; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + chip->base =devm_ioremap_resource (dev, res); +if (IS_ERR (chip->base)) { +dev_err (dev,"unable to map I/O memory\n" ); +return PTR_ERR (chip->base); + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (res) { + chip->io_ctrl =devm_ioremap_resource (dev, res); +if (IS_ERR (chip->io_ctrl)) { +dev_err (dev,"unable to map I/O memory\n" ); +return PTR_ERR (chip->io_ctrl); + } + } + +spin_lock_init (&chip->lock); + + gc = &chip->gc; + gc->base =-1 ; + gc->ngpio = ngpios; + gc->label =dev_name (dev); + gc->dev = dev; + gc->of_node = dev->of_node; + gc->request = cygnus_gpio_request; + gc->free = cygnus_gpio_free; + gc->direction_input = cygnus_gpio_direction_input; + gc->direction_output = cygnus_gpio_direction_output; + gc->set = cygnus_gpio_set; + gc->get = cygnus_gpio_get; + + ret =gpiochip_add (gc); +if (ret <0 ) { +dev_err (dev,"unable to add GPIO chip\n" ); +return ret; + } + + ret =cygnus_gpio_pinmux_add_range (chip); +if (ret && ret != -ENODEV ) { +dev_err (dev,"unable to add GPIO pin range\n" ); + goto err_rm_gpiochip; + } + + ret =cygnus_gpio_register_pinconf (chip); +if (ret) { +dev_err (dev,"unable to register pinconf\n" ); + goto err_rm_range; + } + +/* optional GPIO interrupt support */ + irq =platform_get_irq (pdev,0 ); +if (irq) { + ret =gpiochip_irqchip_add (gc, &cygnus_gpio_irq_chip,0 , + handle_simple_irq,IRQ_TYPE_NONE ); +if (ret) { +dev_err (dev,"no GPIO irqchip\n" ); + goto err_unregister_pinconf; + } + +gpiochip_set_chained_irqchip (gc, &cygnus_gpio_irq_chip, irq, + cygnus_gpio_irq_handler); + } + +return 0 ; + +err_unregister_pinconf: +cygnus_gpio_unregister_pinconf (chip); + +err_rm_range: +cygnus_gpio_pinmux_remove_range (chip); + +err_rm_gpiochip: +gpiochip_remove (gc);
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 909
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+ +return ret; +} + +static struct platform_driver cygnus_gpio_driver = { + .driver = { + .name ="cygnus-gpio" , + .of_match_table = cygnus_gpio_of_match, + }, + .probe = cygnus_gpio_probe,
The same comment about suppress_bind_attrs.
Quoted 14 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +11
-0+}; + +static int __init cygnus_gpio_init (void ) +{ +return platform_driver_probe (&cygnus_gpio_driver, cygnus_gpio_probe); +} +arch_initcall_sync (cygnus_gpio_init); + +MODULE_AUTHOR ("Ray Jui <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom Cygnus GPIO Driver" ); +MODULE_LICENSE ("GPL v2" );Signature · 1 line
1.7.9.5
Thanks.
Signature · 1 line
Dmitry
Ray Jui
maintainerRe: [PATCH v7 2/4] pinctrl: cygnus: add gpio/pinconf driver
Quoted 158 lines · Dmitry Torokhov
Quoted 157 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]>--- drivers/pinctrl/bcm/Kconfig | 22 + drivers/pinctrl/bcm/Makefile | 1 + drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c | 920 +++++++++++++++++++++++++++++ 3 files changed, 943 insertions(+) create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-gpio.cdrivers/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.odrivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +90
-0@@ -0,0 +1,920 @@ +/* +* Copyright (C) 2014-2015 Broadcom Corporation +* +* 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 version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This file contains the Broadcom Cygnus GPIO driver that supports 3 +* GPIO controllers on Cygnus including the ASIU GPIO controller, the +* chipCommonG GPIO controller, and the always-on GPIO controller. Basic +* PINCONF such as bias pull up/down, and drive strength are also supported +* in this driver. +* +* Pins from the ASIU GPIO can be individually muxed to GPIO function, +* through the interaction with the Cygnus IOMUX controller +*/ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/ioport.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> + +#include "../pinctrl-utils.h" + +#define CYGNUS_GPIO_DATA_IN_OFFSET 0x00 +#define CYGNUS_GPIO_DATA_OUT_OFFSET 0x04 +#define CYGNUS_GPIO_OUT_EN_OFFSET 0x08 +#define CYGNUS_GPIO_IN_TYPE_OFFSET 0x0c +#define CYGNUS_GPIO_INT_DE_OFFSET 0x10 +#define CYGNUS_GPIO_INT_EDGE_OFFSET 0x14 +#define CYGNUS_GPIO_INT_MSK_OFFSET 0x18 +#define CYGNUS_GPIO_INT_STAT_OFFSET 0x1c +#define CYGNUS_GPIO_INT_MSTAT_OFFSET 0x20 +#define CYGNUS_GPIO_INT_CLR_OFFSET 0x24 +#define CYGNUS_GPIO_PAD_RES_OFFSET 0x34 +#define CYGNUS_GPIO_RES_EN_OFFSET 0x38 + +/* drive strength control for ASIU GPIO */ +#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 + +/* drive strength control for CCM/CRMU (AON) GPIO */ +#define CYGNUS_GPIO_DRV0_CTRL_OFFSET 0x00 + +#define GPIO_BANK_SIZE 0x200 +#define NGPIOS_PER_BANK 32 +#define GPIO_BANK (pin) ((pin) / NGPIOS_PER_BANK) + +#define CYGNUS_GPIO_REG (pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg)) +#define CYGNUS_GPIO_SHIFT (pin) ((pin) % NGPIOS_PER_BANK) + +#define GPIO_DRV_STRENGTH_BIT_SHIFT 20 +#define GPIO_DRV_STRENGTH_BITS 3 +#define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1) + +/* +* Cygnus GPIO core +* +* @dev: pointer to device +* @base: I/O register base for Cygnus GPIO controller +* @io_ctrl: I/O register base for certain type of Cygnus GPIO controller that +* has the PINCONF support implemented outside of the GPIO block +* @lock: lock to protect access to I/O registers +* @gc: GPIO chip +* @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs +* @pinmux_is_supported: flag to indicate this GPIO controller contains pins +* that can be individually muxed to GPIO +* @pctl: pointer to pinctrl_dev +* @pctldesc: pinctrl descriptor +* @pins: pointer to array of pins +*/ +struct cygnus_gpio { +struct device *dev; + +void __iomem *base; +void __iomem *io_ctrl; +
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 96
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +6
-0+spinlock_t lock; + +struct gpio_chip gc; +unsigned num_banks; + +int pinmux_is_supported;bool?
Yes. Will do.
Quoted 294 lines
Quoted 294 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +294
-0+ +struct pinctrl_dev *pctl; +struct pinctrl_desc pctldesc; +struct pinctrl_pin_desc *pins; +}; + +static struct cygnus_gpio *to_cygnus_gpio (struct gpio_chip *gc) +{ + return container_of(gc, struct cygnus_gpio, gc); +} + +/* +* Mapping from PINCONF pins to GPIO pins is 1-to-1 +*/ +static unsigned cygnus_pin_to_gpio (unsigned pin) +{ +return pin; +} + +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); +} + +/** +* cygnus_set_bit - set or clear one bit (corresponding to the GPIO pin) in a +* Cygnus GPIO register +* +* @cygnus_gpio: Cygnus GPIO device +* @reg: register offset +* @gpio: GPIO pin +* @set: set or clear. 1 - set; 0 -clear +*/ +static void cygnus_set_bit (struct cygnus_gpio *chip,unsigned int reg, +unsigned gpio,int set) +{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + 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) +{ +unsigned int offset =CYGNUS_GPIO_REG (gpio, reg); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + val =cygnus_readl (chip, offset) &BIT (shift); +if (val) +return 1 ; +else +return 0 ; +} + +static void cygnus_gpio_irq_handler (unsigned int irq,struct irq_desc *desc) +{ +struct gpio_chip *gc =irq_desc_get_handler_data (desc); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +struct irq_chip *irq_chip =irq_desc_get_chip (desc); +int i, bit; + +chained_irq_enter (irq_chip, desc); + +/* go through the entire GPIO banks and handle all interrupts */ +for (i =0 ; i < chip->num_banks; i++) { +unsigned long val =cygnus_readl (chip, + (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_MSTAT_OFFSET ); + +for_each_set_bit (bit, &val,NGPIOS_PER_BANK ) { +unsigned pin =NGPIOS_PER_BANK * i + bit; +int child_irq =irq_find_mapping (gc->irqdomain, pin); + +/* +* Clear the interrupt before invoking the +* handler, so we do not leave any window +*/ +cygnus_writel (chip, (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_CLR_OFFSET ,BIT (bit)); + +generic_handle_irq (child_irq); + } + } + +chained_irq_exit (irq_chip, desc); +} + + +static void cygnus_gpio_irq_ack (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = d->hwirq; +unsigned int offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_INT_CLR_OFFSET ); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val =BIT (shift); + +cygnus_writel (chip, offset, val); +} + +/** +* cygnus_gpio_irq_set_mask - mask/unmask a GPIO interrupt +* +* @d: IRQ chip data +* @mask: mask/unmask GPIO interrupt. 0 - mask (disable); 1 - unmask (enable) +*/ +static void cygnus_gpio_irq_set_mask (struct irq_data *d,int mask) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned gpio = d->hwirq; + +cygnus_set_bit (chip,CYGNUS_GPIO_INT_MSK_OFFSET , gpio, mask); +} + +static void cygnus_gpio_irq_mask (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_gpio_irq_set_mask (d,0 ); +spin_unlock_irqrestore (&chip->lock, flags); +} + +static void cygnus_gpio_irq_unmask (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_gpio_irq_set_mask (d,1 ); +spin_unlock_irqrestore (&chip->lock, flags); +} + +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 ; +unsigned long flags; + +switch (type &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_EDGE_RISING : + edge_lvl =1 ; +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 ; +} + +static struct irq_chip cygnus_gpio_irq_chip = { + .name ="bcm-cygnus-gpio" , + .irq_ack = cygnus_gpio_irq_ack, + .irq_mask = cygnus_gpio_irq_mask, + .irq_unmask = cygnus_gpio_irq_unmask, + .irq_set_type = cygnus_gpio_irq_set_type, +}; + +/* +* 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); +} + +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); +} + +static int cygnus_gpio_direction_input (struct gpio_chip *gc,unsigned gpio) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_OUT_EN_OFFSET , gpio,0 ); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set input\n" , gpio); + +return 0 ; +} + +static int cygnus_gpio_direction_output (struct gpio_chip *gc,unsigned gpio, +int value) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_OUT_EN_OFFSET , gpio,1 ); +cygnus_set_bit (chip,CYGNUS_GPIO_DATA_OUT_OFFSET , gpio, value); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set output, value:%d\n" , gpio, value); + +return 0 ; +} + +static void cygnus_gpio_set (struct gpio_chip *gc,unsigned gpio,int value) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); +cygnus_set_bit (chip,CYGNUS_GPIO_DATA_OUT_OFFSET , gpio, value); +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set, value:%d\n" , gpio, value); +} + +static int cygnus_gpio_get (struct gpio_chip *gc,unsigned gpio) +{ +struct cygnus_gpio *chip =to_cygnus_gpio (gc); +unsigned int offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_DATA_IN_OFFSET ); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); + +return !!(cygnus_readl (chip, offset) &BIT (shift)); +} + +static int cygnus_get_groups_count (struct pinctrl_dev *pctldev) +{ +return 1 ; +} + +/* +* Only one group: "gpio_grp", since this local pinctrl device only performs
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 396
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +6
-0+* GPIO specific PINCONF configurations +*/ +static const char *cygnus_get_group_name (struct pinctrl_dev *pctldev, +unsigned selector) +{ +Extra blank line.
Thanks!
Quoted 339 lines
Quoted 315 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +315
-0+return "gpio_grp" ; +} + +static const struct pinctrl_ops cygnus_pctrl_ops = { + .get_groups_count = cygnus_get_groups_count, + .get_group_name = cygnus_get_group_name, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int cygnus_gpio_set_pull (struct cygnus_gpio *chip,unsigned gpio, +int disable,int pull_up) +{ +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); + +if (disable) { +cygnus_set_bit (chip,CYGNUS_GPIO_RES_EN_OFFSET , gpio,0 ); + }else { +cygnus_set_bit (chip,CYGNUS_GPIO_PAD_RES_OFFSET , gpio, + pull_up); +cygnus_set_bit (chip,CYGNUS_GPIO_RES_EN_OFFSET , gpio,1 ); + } + +spin_unlock_irqrestore (&chip->lock, flags); + +dev_dbg (chip->dev,"gpio:%u set pullup:%d\n" , gpio, pull_up); + +return 0 ; +} + +static void cygnus_gpio_get_pull (struct cygnus_gpio *chip,unsigned gpio, +int *disable,int *pull_up) +{ +unsigned long flags; + +spin_lock_irqsave (&chip->lock, flags); + *disable = !cygnus_get_bit (chip,CYGNUS_GPIO_RES_EN_OFFSET , gpio); + *pull_up =cygnus_get_bit (chip,CYGNUS_GPIO_PAD_RES_OFFSET , gpio); +spin_unlock_irqrestore (&chip->lock, flags); +} + +static int cygnus_gpio_set_strength (struct cygnus_gpio *chip,unsigned gpio, +unsigned strength) +{ +void __iomem *base; +unsigned int i, offset, shift; +u32 val; +unsigned long flags; + +/* make sure drive strength is supported */ +if (strength <2 || strength >16 || (strength %2 )) +return -ENOTSUPP ; + +if (chip->io_ctrl) { + base = chip->io_ctrl; + offset =CYGNUS_GPIO_DRV0_CTRL_OFFSET ; + }else { + base = chip->base; + offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET ); + } + + shift =CYGNUS_GPIO_SHIFT (gpio); + +dev_dbg (chip->dev,"gpio:%u set drive strength:%d mA\n" , gpio, + strength); + +spin_lock_irqsave (&chip->lock, flags); + strength = (strength /2 ) -1 ; +for (i =0 ; i <GPIO_DRV_STRENGTH_BITS ; i++) { + val =readl (base + offset); + val &= ~BIT (shift); + val |= ((strength >> i) &0x1 ) << shift; +writel (val, base + offset); + offset +=4 ; + } +spin_unlock_irqrestore (&chip->lock, flags); + +return 0 ; +} + +static int cygnus_gpio_get_strength (struct cygnus_gpio *chip,unsigned gpio, +u16 *strength) +{ +void __iomem *base; +unsigned int i, offset, shift; +u32 val; +unsigned long flags; + +if (chip->io_ctrl) { + base = chip->io_ctrl; + offset =CYGNUS_GPIO_DRV0_CTRL_OFFSET ; + }else { + base = chip->base; + offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET ); + } + + shift =CYGNUS_GPIO_SHIFT (gpio); + +spin_lock_irqsave (&chip->lock, flags); + *strength =0 ; +for (i =0 ; i <GPIO_DRV_STRENGTH_BITS ; i++) { + val =readl (base + offset) &BIT (shift); + val >>= shift; + *strength += (val << i); + offset +=4 ; + } + +/* convert to mA */ + *strength = (*strength +1 ) *2 ; +spin_unlock_irqrestore (&chip->lock, flags); + +return 0 ; +} + +static int cygnus_pin_config_get (struct pinctrl_dev *pctldev,unsigned pin, +unsigned long *config) +{ +struct cygnus_gpio *chip =pinctrl_dev_get_drvdata (pctldev); +enum pin_config_param param =pinconf_to_config_param (*config); +unsigned gpio =cygnus_pin_to_gpio (pin); +u16 arg; +int disable, pull_up, ret; + +switch (param) { +case PIN_CONFIG_BIAS_DISABLE : +cygnus_gpio_get_pull (chip, gpio, &disable, &pull_up); +if (disable) +return 0 ; +else +return -EINVAL ; + +case PIN_CONFIG_BIAS_PULL_UP : +cygnus_gpio_get_pull (chip, gpio, &disable, &pull_up); +if (!disable && pull_up) +return 0 ; +else +return -EINVAL ; + +case PIN_CONFIG_BIAS_PULL_DOWN : +cygnus_gpio_get_pull (chip, gpio, &disable, &pull_up); +if (!disable && !pull_up) +return 0 ; +else +return -EINVAL ; + +case PIN_CONFIG_DRIVE_STRENGTH : + ret =cygnus_gpio_get_strength (chip, gpio, &arg); +if (ret) +return ret; +else + *config =pinconf_to_config_packed (param, arg); + +return 0 ; + +default : +return -ENOTSUPP ; + } + +return -ENOTSUPP ; +} + +static int cygnus_pin_config_set (struct pinctrl_dev *pctldev,unsigned pin, +unsigned long *configs,unsigned num_configs) +{ +struct cygnus_gpio *chip =pinctrl_dev_get_drvdata (pctldev); +enum pin_config_param param; +u16 arg; +unsigned i, gpio =cygnus_pin_to_gpio (pin); +int ret = -ENOTSUPP ; + +for (i =0 ; i < num_configs; i++) { + param =pinconf_to_config_param (configs[i]); + arg =pinconf_to_config_argument (configs[i]); + +switch (param) { +case PIN_CONFIG_BIAS_DISABLE : + ret =cygnus_gpio_set_pull (chip, gpio,1 ,0 ); +if (ret <0 ) + goto out; +break ; + +case PIN_CONFIG_BIAS_PULL_UP : + ret =cygnus_gpio_set_pull (chip, gpio,0 ,1 ); +if (ret <0 ) + goto out; +break ; + +case PIN_CONFIG_BIAS_PULL_DOWN : + ret =cygnus_gpio_set_pull (chip, gpio,0 ,0 ); +if (ret <0 ) + goto out; +break ; + +case PIN_CONFIG_DRIVE_STRENGTH : + ret =cygnus_gpio_set_strength (chip, gpio, arg); +if (ret <0 ) + goto out; +break ; + +default : +dev_err (chip->dev,"invalid configuration\n" ); +return -ENOTSUPP ; + } + }/* for each config */ + +out: +return ret; +} + +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, +}; + +/* +* 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 } + +/* +* 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; + +/* 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); +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 */ +for (i =0 ; i <ARRAY_SIZE (cygnus_gpio_pintable); i++) { + ret = gpiochip_add_pin_range(gc, dev_name(&pinmux_pdev->dev),drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 721
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+ 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_rm_pin_range; + } + } + + chip->pinmux_is_supported =1 ;chip->pinmux_is_supported = true;?
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 725
Quoted 4 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +4
-0+return 0 ; + +err_rm_pin_range: +gpiochip_remove_pin_ranges (gc);I think you need:
put_dveice(&pinmux_pdev->dev);
Quoted 9 lines
since
of_find_device_by_nodecallsbus_find_device()that takes reference to found device.... And now that I look at this majority of users of
of_find_device_by_node()is broken like that :(BTW, it looks like you only need
pinmux_devfor it's name so you probably need to drop reference in success path as well.
Oh wow! Really good to know. Will fix!
Quoted 27 lines
Quoted 27 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +27
-0+return ret; +} + +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); +} + +/* +* Cygnus GPIO controller supports some PINCONF related configurations such as +* pull up, pull down, and drive strength, when the pin is configured to GPIO +* +* Here a local pinctrl device is created with simple 1-to-1 pin mapping to the +* local GPIO pins +*/ +static int cygnus_gpio_register_pinconf (struct cygnus_gpio *chip) +{ +struct pinctrl_desc *pctldesc = &chip->pctldesc; +struct pinctrl_pin_desc *pins; +struct gpio_chip *gc = &chip->gc; +int i, ret; + + pins =devm_kcalloc (chip->dev, gc->ngpio,sizeof (*pins),GFP_KERNEL ); +if (!pins)
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 758
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +6
-0+return -ENOMEM ; + chip->pins = pins; + +for (i =0 ; i < gc->ngpio; i++) { + pins[i].number = i; + pins[i].name =kasprintf (GFP_KERNEL ,"gpio-%d" , i);We have
devm_kasprintf().
I was not aware of that. Okay I'll change to devm_kasprintf so I can get rid of some memory free code below. Thanks!
Quoted 32 lines
Quoted 32 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +32
-0+if (!pins[i].name) { + ret = -ENOMEM ; + goto err_kfree; + } + } + + pctldesc->name =dev_name (chip->dev); + pctldesc->pctlops = &cygnus_pctrl_ops; + pctldesc->pins = pins; + pctldesc->npins = gc->ngpio; + pctldesc->confops = &cygnus_pconf_ops; + + chip->pctl =pinctrl_register (pctldesc, chip->dev, chip); +if (!chip->pctl) { +dev_err (chip->dev,"unable to register pinctrl device\n" ); + ret = -EINVAL ; + goto err_kfree; + } + +return 0 ; + +err_kfree: +for (i =0 ; i < gc->ngpio; i++) +kfree (pins[i].name); + +return ret; +} + +static void cygnus_gpio_unregister_pinconf (struct cygnus_gpio *chip) +{ +struct gpio_chip *gc = &chip->gc; +int i;
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 796
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +6
-0+ +if (chip->pctl) +pinctrl_unregister (chip->pctl); + +for (i =0 ; i < gc->ngpio; i++) +kfree (chip->pins[i].name);Should not be needed if you use
devm_kasprintf.
Yes!
Quoted 107 lines
Quoted 107 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +107
-0+} + +static const struct of_device_id cygnus_gpio_of_match[] = { + { .compatible ="brcm,cygnus-gpio" }, + { } +}; +MODULE_DEVICE_TABLE (of, cygnus_gpio_of_match); + +static int cygnus_gpio_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct resource *res; +struct cygnus_gpio *chip; +struct gpio_chip *gc; +u32 ngpios; +int irq, ret; + + chip =devm_kzalloc (dev,sizeof (*chip),GFP_KERNEL ); +if (!chip) +return -ENOMEM ; + + chip->dev = dev; +platform_set_drvdata (pdev, chip); + +if (of_property_read_u32 (dev->of_node,"ngpios" , &ngpios)) { +dev_err (dev,"missing ngpios DT property\n" ); +return -ENODEV ; + } + chip->num_banks = (ngpios +NGPIOS_PER_BANK -1 ) /NGPIOS_PER_BANK ; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + chip->base =devm_ioremap_resource (dev, res); +if (IS_ERR (chip->base)) { +dev_err (dev,"unable to map I/O memory\n" ); +return PTR_ERR (chip->base); + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (res) { + chip->io_ctrl =devm_ioremap_resource (dev, res); +if (IS_ERR (chip->io_ctrl)) { +dev_err (dev,"unable to map I/O memory\n" ); +return PTR_ERR (chip->io_ctrl); + } + } + +spin_lock_init (&chip->lock); + + gc = &chip->gc; + gc->base =-1 ; + gc->ngpio = ngpios; + gc->label =dev_name (dev); + gc->dev = dev; + gc->of_node = dev->of_node; + gc->request = cygnus_gpio_request; + gc->free = cygnus_gpio_free; + gc->direction_input = cygnus_gpio_direction_input; + gc->direction_output = cygnus_gpio_direction_output; + gc->set = cygnus_gpio_set; + gc->get = cygnus_gpio_get; + + ret =gpiochip_add (gc); +if (ret <0 ) { +dev_err (dev,"unable to add GPIO chip\n" ); +return ret; + } + + ret =cygnus_gpio_pinmux_add_range (chip); +if (ret && ret != -ENODEV ) { +dev_err (dev,"unable to add GPIO pin range\n" ); + goto err_rm_gpiochip; + } + + ret =cygnus_gpio_register_pinconf (chip); +if (ret) { +dev_err (dev,"unable to register pinconf\n" ); + goto err_rm_range; + } + +/* optional GPIO interrupt support */ + irq =platform_get_irq (pdev,0 ); +if (irq) { + ret =gpiochip_irqchip_add (gc, &cygnus_gpio_irq_chip,0 , + handle_simple_irq,IRQ_TYPE_NONE ); +if (ret) { +dev_err (dev,"no GPIO irqchip\n" ); + goto err_unregister_pinconf; + } + +gpiochip_set_chained_irqchip (gc, &cygnus_gpio_irq_chip, irq, + cygnus_gpio_irq_handler); + } + +return 0 ; + +err_unregister_pinconf: +cygnus_gpio_unregister_pinconf (chip); + +err_rm_range: +cygnus_gpio_pinmux_remove_range (chip); + +err_rm_gpiochip: +gpiochip_remove (gc); + +return ret; +} +
Quoted 9 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 909
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +6
-0+static struct platform_driver cygnus_gpio_driver = { + .driver = { + .name ="cygnus-gpio" , + .of_match_table = cygnus_gpio_of_match, + }, + .probe = cygnus_gpio_probe,The same comment about
suppress_bind_attrs.
Okay. Will do!
Quoted 8 lines
Quoted 8 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +8
-0+}; + +static int __init cygnus_gpio_init (void ) +{ +return platform_driver_probe (&cygnus_gpio_driver, cygnus_gpio_probe); +} +arch_initcall_sync (cygnus_gpio_init); +
Quoted 9 lines
Quoted 6 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +3
-0+MODULE_AUTHOR ("Ray Jui <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom Cygnus GPIO Driver" ); +MODULE_LICENSE ("GPL v2" );Signature · 1 line
1.7.9.5Thanks.
Thanks for the review, Dmitry!
Ray
Ray Jui
maintainerPATCH v7 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 v7 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
Ray Jui
maintainerv4 cover Add pinctrl support to Broadcom Cygnus SoC
In reply to a message not in the archiveThis patchset contains the initial pinctrl (IOMUX) support for the Broadcom Cygnus SoC. The Cygnus IOMUX controller supports group based mux configuration and allows certain pins to be muxed to GPIO function individually
Changes from v3:
- Fix the driver to have more proper use of "const" in various places
- Other minor improvements
Changes from v2:
- Consolidate all Broadcom pinctrl drivers into drivers/pinctrl/bcm/*
- Change the Cygnus IOMUX driver to use standard Linux pinctrl subnode
properties such as "function" and "groups" for pinmux configuration, instead of non-standard properties such as "brcm,function" and "brcm,group"
- Use real function names like "spi0", "lcd", "key", and etc. instead of HW
specific mux names like "alt1", "alt2", "alt3", and etc.
- Add suffix "grp" to all group names
- Add support to allow individual pins to be muxed to GPIO function through
subsystem callbacks "gpio_request_enable" and "gpio_disable_free", and get rid of all GPIO groups
- Other minor improvements in the driver
Changes from v1:
- Fix a typo in device tree binding document
Ray Jui (4):
pinctrl: bcm: consolidate Broadcom pinctrl drivers
pinctrl: Broadcom Cygnus pinctrl device tree binding
pinctrl: cygnus: add initial IOMUX driver support
ARM: dts: enable IOMUX for Broadcom Cygnus
.../bindings/pinctrl/brcm,cygnus-pinmux.txt | 157 +++ arch/arm/boot/dts/bcm-cygnus.dtsi | 6 + drivers/pinctrl/Kconfig | 19 +- drivers/pinctrl/Makefile | 4 +- drivers/pinctrl/bcm/Kconfig | 34 + drivers/pinctrl/bcm/Makefile | 5 + drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 1455 ++++++++++++++++++++ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1072 ++++++++++++++ drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 1088 +++++++++++++++ drivers/pinctrl/pinctrl-bcm281xx.c | 1455 -------------------- drivers/pinctrl/pinctrl-bcm2835.c | 1072 -------------- 11 files changed, 3820 insertions(+), 2547 deletions(-) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt create mode 100644 drivers/pinctrl/bcm/Kconfig create mode 100644 drivers/pinctrl/bcm/Makefile create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm281xx.c create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm2835.c create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-mux.c delete mode 100644 drivers/pinctrl/pinctrl-bcm281xx.c delete mode 100644 drivers/pinctrl/pinctrl-bcm2835.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 1/4 pinctrl: bcm: consolidate Broadcom pinctrl drivers
Consolidate Broadcom pinctrl drivers into drivers/pinctrl/bcm/*
--- drivers/pinctrl/Kconfig | 19 +- drivers/pinctrl/Makefile | 4 +- drivers/pinctrl/bcm/Kconfig | 21 + drivers/pinctrl/bcm/Makefile | 4 + drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 1455 ++++++++++++++++++++++++++++++++ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1072 +++++++++++++++++++++++ drivers/pinctrl/pinctrl-bcm281xx.c | 1455 -------------------------------- drivers/pinctrl/pinctrl-bcm2835.c | 1072 ----------------------- 8 files changed, 2555 insertions(+), 2547 deletions(-) create mode 100644 drivers/pinctrl/bcm/Kconfig create mode 100644 drivers/pinctrl/bcm/Makefile create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm281xx.c create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm2835.c delete mode 100644 drivers/pinctrl/pinctrl-bcm281xx.c delete mode 100644 drivers/pinctrl/pinctrl-bcm2835.c
drivers/pinctrl/Kconfig +1 -18
@@ -67,24 +67,6 @@ config PINCTRL_AT91 help Say Y here to enable the at91 pinctrl driver -config PINCTRL_BCM2835 - bool - select PINMUX - select PINCONF - -config PINCTRL_BCM281XX - bool "Broadcom BCM281xx pinctrl driver" - depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) - select PINMUX - select PINCONF - select GENERIC_PINCONF - select REGMAP_MMIO - help - Say Y here to support Broadcom BCM281xx pinctrl driver, which is used - for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351, - BCM28145, and BCM28155 SoCs. This driver requires the pinctrl - framework. GPIO is provided by a separate GPIO driver. - config PINCTRL_LANTIQ bool depends on LANTIQ
@@ -191,6 +173,7 @@ config PINCTRL_PALMAS open drain configuration for the Palmas series devices like TPS65913, TPS80036 etc. +source "drivers/pinctrl/bcm/Kconfig" source "drivers/pinctrl/berlin/Kconfig" source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/intel/Kconfig"
drivers/pinctrl/Makefile +2 -2
@@ -14,8 +14,6 @@ obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o -obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o -obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
@@ -36,6 +34,8 @@ obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o +obj-$(CONFIG_ARCH_BCM) += bcm/ +obj-$(CONFIG_ARCH_BCM2835) += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += freescale/ obj-$(CONFIG_X86) += intel/
drivers/pinctrl/bcm/Kconfig new file +21 -0
@@ -0,0 +1,21 @@ +# +# Broadcom pinctrl drivers +# + +config PINCTRL_BCM281XX + bool "Broadcom BCM281xx pinctrl driver" + depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) + select PINMUX + select PINCONF + select GENERIC_PINCONF + select REGMAP_MMIO + help + Say Y here to support Broadcom BCM281xx pinctrl driver, which is used + for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351, + BCM28145, and BCM28155 SoCs. This driver requires the pinctrl + framework. GPIO is provided by a separate GPIO driver. + +config PINCTRL_BCM2835 + bool + select PINMUX + select PINCONF
drivers/pinctrl/bcm/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +# Broadcom pinctrl support + +obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o +obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
drivers/pinctrl/bcm/pinctrl-bcm281xx.c new file +1455 -0
1,455 lines not on this page · raw message
drivers/pinctrl/bcm/pinctrl-bcm2835.c new file +1072 -0
1,072 lines not on this page · raw message
drivers/pinctrl/pinctrl-bcm281xx.c deleted +0 -1455
401 lines not on this page · raw message
drivers/pinctrl/pinctrl-bcm2835.c deleted +0 -1072
1,072 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.9.5
Part of the diff is not shown here. View the raw message.
Re: [PATCH v4 1/4] pinctrl: bcm: consolidate Broadcom pinctrl drivers
Quoted 3 lines · Ray Jui
Consolidate Broadcom pinctrl drivers into
drivers/pinctrl/bcm/*Signed-off-by Ray Jui <[email protected]>
This patch doesn't apply so it needs to be rebased on v4.0-rc1 and resent.
And also when just moving files, always do this:
git format-patch -M ...
So that file movement is detected, and the patch will apply nicely even if the contents of the file(s) have changed.
Can you also combine this series with the v9 GPIO etc series and send out ONE big patch set that I can look at because right now I'm getting really confused ...
I'll look over the rest and see if there is some remaining technical comments (hopefully mainly patch mechanics remains).
Yours,
Linus Walleij
Ray Jui
maintainerRe: [PATCH v4 1/4] pinctrl: bcm: consolidate Broadcom pinctrl drivers
Hi Linus,
Quoted 19 lines · Linus Walleij
Quoted 3 lines · Ray Jui
Consolidate Broadcom pinctrl drivers into
drivers/pinctrl/bcm/*Signed-off-by Ray Jui <[email protected]>This patch doesn't apply so it needs to be rebased on v4.0-rc1 and resent.
And also when just moving files, always do this:
git format-patch -M ...
So that file movement is detected, and the patch will apply nicely even if the contents of the file(s) have changed.
Can you also combine this series with the v9 GPIO etc series and send out ONE big patch set that I can look at because right now I'm getting really confused ...
Quoted 6 lines
I'll look over the rest and see if there is some remaining technical comments (hopefully mainly patch mechanics remains).
Yours,
Linus Walleij
Okay. I'll rebase to v4.0-rc1 and consolidate both pinmux and gpio pinctrl patch series into one, which will be PATCH v5.
Thanks,
Ray
Ray Jui
maintainerPATCH v4 2/4 pinctrl: Broadcom Cygnus pinctrl device tree binding
In reply to Ray JuiDevice tree binding documentation for Broadcom Cygnus IOMUX driver
--- .../bindings/pinctrl/brcm,cygnus-pinmux.txt | 157 ++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt
Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt new file +157 -0
@@ -0,0 +1,157 @@ +Broadcom Cygnus IOMUX Controller + +The Cygnus IOMUX controller supports group based mux configuration. In +addition, certain pins can be muxed to GPIO function individually. + +Required properties: + +- compatible: + Must be "brcm,cygnus-pinmux" + +- reg: + Define the base and range of the I/O address space that contains the Cygnus +IOMUX registers + +Required properties in child nodes: + +- function: + The mux function to select + +- groups: + The list of groups to select with a given function + +Each child node represents a configuration. Client devices reference the child +node to enable a mux configuration + +For more details, refer to +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +For example: + + pinmux: pinmux@0x0301d0c8 { + compatible = "brcm,cygnus-pinmux"; + reg = <0x0301d0c8 0x1b0>; + + i2s_0: i2s_0 { + function = "i2s0"; + groups = "i2s0_0_grp", "i2s0_1_grp"; + }; + + i2s_1: i2s_1 { + function = "i2s1"; + groups = "i2s1_0_grp", "i2s1_1_grp"; + }; + + i2s_2: i2s_2 { + function = "i2s2"; + groups = "i2s2_0_grp", "i2s2_1_grp", "i2s2_2_grp", + "i2s2_3_grp", "i2s2_4_grp"; + }; + + spi_0: spi_0 { + function = "spi0"; + groups = "spi0_grp"; + }; + } + + spi0@18028000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x18028000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-0 = <&spi_0>; + clocks = <&axi81_clk>; + clock-names = "apb_pclk"; + }; + +List of supported functions and groups in Cygnus: + +"i2s0": "i2s0_0_grp", "i2s0_1_grp" + +"i2s1": "i2s1_0_grp", "i2s1_1_grp" + +"i2s2": "i2s2_0_grp", "i2s2_1_grp", "i2s2_2_grp", "i2s2_3_grp", "i2s2_4_grp" + +"spdif": "spdif_grp" + +"pwm0": "pwm0_grp" + +"pwm1": "pwm1_grp" + +"pwm2": "pwm2_grp" + +"pwm3": "pwm3_grp" + +"pwm4": "pwm4_grp" + +"pwm5": "pwm5_grp" + +"key": "key0_grp", "key1_grp", "key2_grp", "key3_grp", "key4_grp", "key5_grp", +"key6_grp", "key7_grp", "key8_grp", "key9_grp", "key10_grp", "key11_grp", +"key12_grp", "key13_grp", "key14_grp", "key15_grp" + +"audio_dte": "audio_dte0_grp", "audio_dte1_grp", "audio_dte2_grp", "audio_dte3_grp" + +"smart_card0": "smart_card0_grp", "smart_card0_fcb_grp" + +"smart_card1": "smart_card1_grp", "smart_card1_fcb_grp" + +"spi0": "spi0_grp" + +"spi1": "spi1_grp" + +"spi2": "spi2_grp" + +"spi3": "spi3_grp" + +"spi4": "spi4_0_grp", "spi4_1_grp" + +"spi5": "spi5_grp" + +"sw_led0": "sw_led0_0_grp", "sw_led0_1_grp" + +"sw_led1": "sw_led1_grp" + +"sw_led2": "sw_led2_0_grp", "sw_led2_1_grp" + +"d1w": "d1w_grp" + +"lcd": "lcd_grp" + +"sram": "sram_0_grp", "sram_1_grp" + +"uart0": "uart0_grp" + +"uart1": "uart1_grp", "uart1_dte_grp" + +"uart2": "uart2_grp" + +"uart3": "uart3_grp" + +"uart4": "uart4_grp" + +"qspi": "qspi_0_grp", "qspi_1_grp" + +"nand": "nand_grp" + +"sdio0": "sdio0_grp", "sdio0_cd_grp", "sdio0_mmc_grp" + +"sdio1": "sdio1_data_0_grp", "sdio1_data_1_grp", "sdio1_cd_grp", +"sdio1_led_grp", "sdio1_mmc_grp" + +"can0": "can0_grp" + +"can1": "can1_grp" + +"cam": "cam_led_grp", "cam_0_grp", "cam_1_grp" + +"bsc1": "bsc1_grp" + +"pcie_clkreq": "pcie_clkreq_grp" + +"usb0_oc": "usb0_oc_grp" + +"usb1_oc": "usb1_oc_grp" + +"usb2_oc": "usb2_oc_grp"
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 3/4 pinctrl: cygnus: add initial IOMUX driver support
In reply to Ray JuiThis adds the initial driver support for the Broadcom Cygnus IOMUX controller. The Cygnus IOMUX controller supports group based mux configuration but allows certain pins to be muxed to GPIO individually
--- drivers/pinctrl/bcm/Kconfig | 13 + drivers/pinctrl/bcm/Makefile | 5 +- drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 1088 ++++++++++++++++++++++++++++++ 3 files changed, 1104 insertions(+), 2 deletions(-) create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
drivers/pinctrl/bcm/Kconfig +13 -0
@@ -19,3 +19,16 @@ config PINCTRL_BCM2835 bool select PINMUX select PINCONF + +config PINCTRL_CYGNUS_MUX + bool "Broadcom Cygnus IOMUX driver" + depends on (ARCH_BCM_CYGNUS || COMPILE_TEST) + select PINMUX + select GENERIC_PINCONF + default ARCH_BCM_CYGNUS + help + Say yes here to enable the Broadcom Cygnus IOMUX driver. + + The Broadcom Cygnus IOMUX driver supports group based IOMUX + configuration, with the exception that certain individual pins + can be overrided to GPIO function
drivers/pinctrl/bcm/Makefile +3 -2
@@ -1,4 +1,5 @@ # Broadcom pinctrl support -obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o -obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o +obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o
drivers/pinctrl/bcm/pinctrl-cygnus-mux.c new file +1088 -0
1,088 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 4/4 ARM: dts: enable IOMUX for Broadcom Cygnus
In reply to Ray JuiThis enables the IOMUX support for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 6 ++++++ 1 file changed, 6 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +6 -0
@@ -54,6 +54,12 @@ /include/ "bcm-cygnus-clock.dtsi" + pinctrl: pinctrl@0x0301d0c8 { + compatible = "brcm,cygnus-pinmux"; + reg = <0x0301d0c8 0x30>, + <0x0301d24c 0x2c>; + }; + amba { #address-cells = <1>; #size-cells = <1>;
Signature · 1 line
1.7.9.5
Re: [PATCH v4 0/4] Add pinctrl support to Broadcom Cygnus SoC
In reply to Ray JuiQuoted 21 lines · Ray Jui
This patchset contains the initial pinctrl (IOMUX) support for the Broadcom Cygnus SoC. The Cygnus IOMUX controller supports group based mux configuration and allows certain pins to be muxed to GPIO function individually
Changes from v3:
- Fix the driver to have more proper use of "const" in various places
- Other minor improvementsChanges from v2:
- Consolidate all Broadcom pinctrl drivers intodrivers/pinctrl/bcm/*
- Change the Cygnus IOMUX driver to use standard Linux pinctrl subnode
properties such as "function" and "groups" for pinmux configuration, instead of non-standard properties such as "brcm,function" and "brcm,group"
- Use real function names like "spi0", "lcd", "key", and etc. instead of HW
specific mux names like "alt1", "alt2", "alt3", and etc.
- Add suffix "grp" to all group names
- Add support to allow individual pins to be muxed to GPIO function through
subsystem callbacks "gpio_request_enable" and "gpio_disable_free", and get rid of all GPIO groups
- Other minor improvements in the driver
Quoted 2 lines
Changes from v1:
- Fix a typo in device tree binding document
FWIW I tested this series on BCM958305K SVK.
Thanks.
Signature · 1 line
Dmitry
Ray Jui
maintainerv8 cover Add gpio/pinconf support to Broadcom Cygnus SoC
In reply to a message not in the archiveThis 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 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 | 907 ++++++++++++++++++++ 6 files changed, 1078 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 v8 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 v8 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 | 907 +++++++++++++++++++++++++++++ 3 files changed, 930 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 +907 -0
907 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v8 2/4] pinctrl: cygnus: add gpio/pinconf driver
Hi Ray,
Quoted 25 lines · Ray Jui
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +25
-0+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; + +/* 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); +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 */ +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);
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 721
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+if (ret) { +dev_err (chip->dev,"unable to add GPIO pin range\n" ); + goto err_put_device; + } + } + + chip->pinmux_is_supported = true; + +/* no need for pinmux_pdev device reference anymore */ +put_device (&pinmux_pdev->dev);
Sorry I did not notice it before, but of_parse_phandle() takes reference to the returned device node, so you need to "put" it here and in error path as well. Actually you can do:
int ret = 0;
pinmux_node = of_parse_phandle(node, "pinmux", 0);
if (!pinmux_node)
return -ENODEV;
pinmux_pdev = of_find_device_by_node(pinmux_node);
/* We do not longer need pinmux node */
of_node_put(pinmux_node);
if (!pinmux_dev)
....
for (..) {
...
if (ret) {
dev_err(...);
break;
}
}
chip->pinmux_is_supported = (ret == 0);
put_device(..);
return ret;
}This way you free resources in the same path.
...
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 901
Quoted 13 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +13
-0+ +static struct platform_driver cygnus_gpio_driver = { + .driver = { + .name ="cygnus-gpio" , + .of_match_table = cygnus_gpio_of_match, + .suppress_bind_attrs = true, + }, + .probe = cygnus_gpio_probe, +}; + +static int __init cygnus_gpio_init (void ) +{ +return platform_driver_probe (&cygnus_gpio_driver, cygnus_gpio_probe);
When I asked you to add ".suppress_bind_attrs = true" I missed the fact that you were using platform_driver_probe() which already does this internally. However platform_driver_probe() can't handle deferred probing, which may or may not be OK. Is there a chance that any of the resources needed by the driver return -EPROBE_DEFER? If not then it is safe to continue using platform_driver_probe() and you can drop suppress_bind_attrs assignment, otherwise it may be better to switch to platform_driver_register().
Thanks.
Signature · 1 line
Dmitry
Ray Jui
maintainerRe: [PATCH v8 2/4] pinctrl: cygnus: add gpio/pinconf driver
Quoted 69 lines · Dmitry Torokhov
Hi Ray,
Quoted 25 lines · Ray Jui
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +25
-0+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; + +/* 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); +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 */ +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);drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 721
Quoted 10 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +10
-0+if (ret) { +dev_err (chip->dev,"unable to add GPIO pin range\n" ); + goto err_put_device; + } + } + + chip->pinmux_is_supported = true; + +/* no need for pinmux_pdev device reference anymore */ +put_device (&pinmux_pdev->dev);Sorry I did not notice it before, but
of_parse_phandle()takes reference to the returned device node, so you need to "put" it here and in error path as well. Actually you can do:int ret = 0; pinmux_node = of_parse_phandle(node, "pinmux", 0); if (!pinmux_node) return -ENODEV; pinmux_pdev = of_find_device_by_node(pinmux_node); /* We do not longer need pinmux node */ of_node_put(pinmux_node); if (!pinmux_dev) .... for (..) { ... if (ret) { dev_err(...); break; } } chip->pinmux_is_supported = (ret == 0); put_device(..); return ret; }
Quoted 2 lines
This way you free resources in the same path.
Thanks. I'll make the change.
Quoted 25 lines
...
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c line 901
Quoted 13 lines
drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c new file +13
-0+ +static struct platform_driver cygnus_gpio_driver = { + .driver = { + .name ="cygnus-gpio" , + .of_match_table = cygnus_gpio_of_match, + .suppress_bind_attrs = true, + }, + .probe = cygnus_gpio_probe, +}; + +static int __init cygnus_gpio_init (void ) +{ +return platform_driver_probe (&cygnus_gpio_driver, cygnus_gpio_probe);When I asked you to add ".suppress_bind_attrs = true" I missed the fact that you were using
platform_driver_probe()which already does this internally. Howeverplatform_driver_probe()can't handle deferred probing, which may or may not be OK. Is there a chance that any of the resources needed by the driver return -EPROBE_DEFER? If not then it is safe to continue usingplatform_driver_probe()and you can dropsuppress_bind_attrsassignment, otherwise it may be better to switch toplatform_driver_register().
Quoted 2 lines
Thanks.
No I do not expect any resource that this driver depends on to return -EPROBE_DEFER. The IOMUX driver that this driver depends on should be initialized before this driver.
I'll drop .suppress_bind_attrs then. Thanks.
Ray
Ray Jui
maintainerPATCH v8 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 v8 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
Ray Jui
maintainerv5 cover Add common clock support for Broadcom iProc architecture
In reply to a message not in the archiveThis patchset contains the initial common clock support for Broadcom's iProc family of SoCs. The iProc clock architecture comprises of various PLLs, e.g., ARMPLL, GENPLL, LCPLL0, MIPIPLL, and etc. An onboard crystal serves as the basic reference clock for these PLLs. Each PLL may have several leaf clocks. One special group of clocks is the ASIU clocks, which are dervied directly from the crystal reference clock.
This patchset also contains the basic clock support for the Broadcom Cygnus SoC, which implements the iProc clock architecture
Changes from v4:
- Add of_clk_get_parent_rate helper function into the clock framework
- Switch to use of_clk_get_parent_rate in the iProc PLL clock driver
Changes from v3:
- Fix incorrect use of passing in of_clk_src_onecell_get when adding ARM PLL and other iProc PLLs as clock provider. These PLLs have zero cells in DT and thefore of_clk_src_simple_get should be used instead
- Rename Cygnus MIPI PLL Channel 2 clock from BCM_CYGNUS_MIPIPLL_CH2_UNUSED to BCM_CYGNUS_MIPIPLL_CH2_V3D, since a 3D graphic rendering engine has been integrated into Cygnus revision B0 and has its core clock running off MIPI PLL Channel 2
- Changed default MIPI PLL VCO frequency from 1.75 GHz to 2.1 GHz. This allows us to derive 300 MHz V3D clock from channel 2 through the post divisor
Changes from v2:
- Re-arrange Cygnus clock/pll init functions so each init function is right next to its clock table
- Removed #defines for number of clocks in Cygnus. Have the number of clocks automatically determined based on array size of the clock table
Changes from v1:
- Separate drivers/clk/Makefile change for drivers/clk/bcm out to a standalone patch
Ray Jui (6):
clk: add of_clk_get_parent_rate function
clk: iproc: define Broadcom iProc clock binding
clk: iproc: add initial common clock support
clk: Change bcm clocks build dependency
clk: cygnus: add clock support for Broadcom Cygnus
ARM: dts: enable clock support for Broadcom Cygnus
arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 ++++++-- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- brcm,iproc-clocks.txt | 178 ++++++++++++ drivers/clk/Makefile | 2 +- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 2 + drivers/clk/bcm/clk-cygnus.c | 277 +++++++++++++++++++ drivers/clk/bcm/clk-iproc-armpll.c | 282 +++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 ++++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 461 +++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 157 +++++++++++ drivers/clk/clk.c | 17 ++ include/dt-bindings/clock/bcm-cygnus.h | 65 +++++ include/linux/clk-provider.h | 6 +- 15 files changed, 2053 insertions(+), 28 deletions(-) create mode 100644 brcm,iproc-clocks.txt create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 1/6 clk: add of_clk_get_parent_rate function
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.
--- drivers/clk/clk.c | 17 +++++++++++++++++ include/linux/clk-provider.h | 6 +++++- 2 files changed, 22 insertions(+), 1 deletion(-)
drivers/clk/clk.c +17 -0
@@ -2581,6 +2581,23 @@ const char *of_clk_get_parent_name(struct device_node *np, int index) }EXPORT_SYMBOL_GPL (of_clk_get_parent_name); +unsigned long of_clk_get_parent_rate (struct device_node *np,int index) +{ +const char *parent_name; +struct clk *parent_clk; + + parent_name =of_clk_get_parent_name (np, index); +if (!parent_name) +return 0 ; + + parent_clk =__clk_lookup (parent_name); +if (!parent_clk) +return 0 ; + +return clk_get_rate (parent_clk); +} +EXPORT_SYMBOL_GPL (of_clk_get_parent_rate); +struct clock_provider {of_clk_init_cb_t clk_init_cb;struct device_node *np;
include/linux/clk-provider.h +5 -1
@@ -585,7 +585,7 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,struct clk *of_clk_src_onecell_get (struct of_phandle_args *clkspec,void *data);int of_clk_get_parent_count (struct device_node *np);const char *of_clk_get_parent_name (struct device_node *np,int index); - +unsigned long of_clk_get_parent_rate (struct device_node *np,int index);void of_clk_init (const struct of_device_id *matches);#else /* !CONFIG_OF */
@@ -614,6 +614,10 @@ static inline const char *of_clk_get_parent_name(struct device_node *np, {return NULL ; } +static unsigned long of_clk_get_parent_rate (struct device_node *np,int index) +{ +return 0 ; +}#define of_clk_init (matches) \ { while (0); }#endif /* CONFIG_OF */
Signature · 1 line
1.7.9.5
Re: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Quoted 10 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.Signed-off-by Ray Jui <[email protected]>
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
In reply to Ray JuiHi Ray,
Quoted 8 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.
I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case? Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Ray Jui
maintainerRe: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Hi Sascha,
Quoted 9 lines · Sascha Hauer
Hi Ray,
Quoted 6 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Quoted 5 lines
Quoted 2 lines
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case?
In the case when clock parent is not found, as you can see from the code, it simply returns zero, just like other clk get rate APIs.
I thought the order of clock registration is based on order of the clock nodes in device tree. It makes sense to me to declare the parent clock before a child clock, so it's guaranteed that the parent is registered before the child.
Quoted 2 lines
Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sure it's not mandatory. But what's wrong with me choosing to initialize the PLL clock to a known frequency before registering it to the framework?
Ray
Re: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Quoted 12 lines · Ray Jui
Hi Sascha,
Quoted 9 lines · Sascha Hauer
Hi Ray,
Quoted 6 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case?
In the case when clock parent is not found, as you can see from the code, it simply returns zero, just like other clk get rate APIs.
Yes, but what do you do with the 0 result then in your PLL initialization?
Quoted 5 lines
I thought the order of clock registration is based on order of the clock nodes in device tree. It makes sense to me to declare the parent clock before a child clock, so it's guaranteed that the parent is registered before the child.
No, you can't rely on that. The order of the device nodes may happen to define the order of clock initialization now, but that may change. device nodes are usually ordered by bus addresses, not by intended initialization order. Even if you reorder them everything must still work.
Quoted 6 lines
Quoted 3 lines
Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sure it's not mandatory. But what's wrong with me choosing to initialize the PLL clock to a known frequency before registering it to the framework?
Appearantly you don't know the (input) frequency of the PLL when registering it to the framework, so the question must be: What's wrong with keeping it uninitialized?
If the PLL is unused then you don't care about it's initialization status. If it happens to be enabled by a bootloader and still unused at late_initcall time the clock framework will disable it so you have a known state then. If a consumer for the PLL appears it's its job to initialize it through the clk api.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Ray Jui
maintainerRe: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Quoted 16 lines · Sascha Hauer
Quoted 15 lines · Ray Jui
Hi Sascha,
Quoted 12 lines · Sascha Hauer
Hi Ray,
Quoted 8 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case?
In the case when clock parent is not found, as you can see from the code, it simply returns zero, just like other clk get rate APIs.
Yes, but what do you do with the 0 result then in your PLL initialization?
As of the current code, it fails the PLL frequency initialization and bails out. Thinking about it more, it actually makes more sense to just warn and still go ahead to register the clock, in which case it will use whatever default frequency after chip power on reset or a frequency configured in the bootloader.
Quoted 6 lines
Quoted 5 lines
I thought the order of clock registration is based on order of the clock nodes in device tree. It makes sense to me to declare the parent clock before a child clock, so it's guaranteed that the parent is registered before the child.
Quoted 6 lines
No, you can't rely on that. The order of the device nodes may happen to define the order of clock initialization now, but that may change. device nodes are usually ordered by bus addresses, not by intended initialization order. Even if you reorder them everything must still work.
Okay I get your point that the order of device nodes may not be relied on for device initialization order. But then another mechanism should be deployed to give developers the option to decide on the clock initialization sequence. It can be optional but it should be there.
Quoted 11 lines
Quoted 6 lines
Quoted 3 lines
Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sure it's not mandatory. But what's wrong with me choosing to initialize the PLL clock to a known frequency before registering it to the framework?
Appearantly you don't know the (input) frequency of the PLL when registering it to the framework, so the question must be: What's wrong with keeping it uninitialized?
Quoted 8 lines
If the PLL is unused then you don't care about it's initialization status. If it happens to be enabled by a bootloader and still unused at
late_initcalltime the clock framework will disable it so you have a known state then. If a consumer for the PLL appears it's its job to initialize it through the clk api.Sascha
Okay, what we need here is to initialize the PLL to a desired frequency, based on device tree settings (since it will be configured differently, among different boards). This is a PLL that 1) has limited options of frequencies which it can be configured to, and 2) has multiple child clocks, where is a more suitable place to initialize it to the desired frequency than right before registering it to the framework? I know a lot of people do it in the bootloader, but I thought we should be given the flexibility of configuring it in the kernel.
When you say "consumers", do you mean 1) the device driver that uses the PLL; or 2) the device driver that use the child clock of the PLL? If it's case 1), then we don't really have a device driver that directly uses the PLL, and I thought that's quite normal, as most PLLs don't directly feed into any peripherals.
We do have multiple device drivers that use the child clocks of the PLL, but it makes no sense to configure the PLL clock in any of those drivers.
Ray
Re: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Quoted 79 lines · Ray Jui
Quoted 16 lines · Sascha Hauer
Quoted 15 lines · Ray Jui
Hi Sascha,
Quoted 12 lines · Sascha Hauer
Hi Ray,
Quoted 8 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case?
In the case when clock parent is not found, as you can see from the code, it simply returns zero, just like other clk get rate APIs.
Yes, but what do you do with the 0 result then in your PLL initialization?
As of the current code, it fails the PLL frequency initialization and bails out. Thinking about it more, it actually makes more sense to just warn and still go ahead to register the clock, in which case it will use whatever default frequency after chip power on reset or a frequency configured in the bootloader.
Quoted 6 lines
Quoted 5 lines
I thought the order of clock registration is based on order of the clock nodes in device tree. It makes sense to me to declare the parent clock before a child clock, so it's guaranteed that the parent is registered before the child.
Quoted 6 lines
No, you can't rely on that. The order of the device nodes may happen to define the order of clock initialization now, but that may change. device nodes are usually ordered by bus addresses, not by intended initialization order. Even if you reorder them everything must still work.
Okay I get your point that the order of device nodes may not be relied on for device initialization order. But then another mechanism should be deployed to give developers the option to decide on the clock initialization sequence. It can be optional but it should be there.
Quoted 11 lines
Quoted 6 lines
Quoted 3 lines
Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sure it's not mandatory. But what's wrong with me choosing to initialize the PLL clock to a known frequency before registering it to the framework?
Appearantly you don't know the (input) frequency of the PLL when registering it to the framework, so the question must be: What's wrong with keeping it uninitialized?
Quoted 8 lines
If the PLL is unused then you don't care about it's initialization status. If it happens to be enabled by a bootloader and still unused at
late_initcalltime the clock framework will disable it so you have a known state then. If a consumer for the PLL appears it's its job to initialize it through the clk api.Sascha
Okay, what we need here is to initialize the PLL to a desired frequency, based on device tree settings (since it will be configured differently, among different boards). This is a PLL that 1) has limited options of frequencies which it can be configured to, and 2) has multiple child clocks, where is a more suitable place to initialize it to the desired frequency than right before registering it to the framework? I know a lot of people do it in the bootloader, but I thought we should be given the flexibility of configuring it in the kernel.
Quoted 5 lines
When you say "consumers", do you mean 1) the device driver that uses the PLL; or 2) the device driver that use the child clock of the PLL? If it's case 1), then we don't really have a device driver that directly uses the PLL, and I thought that's quite normal, as most PLLs don't directly feed into any peripherals.
I meant 1) and 2). Before a consumer comes along the state of the PLL doesn't matter. When a consumer shows up it has to call clk_prepare_enable which (directly or indirectly) will enable your PLL. Then it's still time to apply the default settings you found out during probe of the PLL.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Re: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Quoting Sascha Hauer (2015-02-26 00:43:19)
Quoted 86 lines · Ray Jui
Quoted 79 lines · Sascha Hauer
Quoted 16 lines · Ray Jui
Quoted 15 lines
Hi Sascha,
Quoted 12 lines · Sascha Hauer
Hi Ray,
Quoted 8 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case?
In the case when clock parent is not found, as you can see from the code, it simply returns zero, just like other clk get rate APIs.
Yes, but what do you do with the 0 result then in your PLL initialization?
As of the current code, it fails the PLL frequency initialization and bails out. Thinking about it more, it actually makes more sense to just warn and still go ahead to register the clock, in which case it will use whatever default frequency after chip power on reset or a frequency configured in the bootloader.
Quoted 6 lines
Quoted 5 lines
I thought the order of clock registration is based on order of the clock nodes in device tree. It makes sense to me to declare the parent clock before a child clock, so it's guaranteed that the parent is registered before the child.
Quoted 6 lines
No, you can't rely on that. The order of the device nodes may happen to define the order of clock initialization now, but that may change. device nodes are usually ordered by bus addresses, not by intended initialization order. Even if you reorder them everything must still work.
Okay I get your point that the order of device nodes may not be relied on for device initialization order. But then another mechanism should be deployed to give developers the option to decide on the clock initialization sequence. It can be optional but it should be there.
Quoted 11 lines
Quoted 6 lines
Quoted 3 lines
Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sure it's not mandatory. But what's wrong with me choosing to initialize the PLL clock to a known frequency before registering it to the framework?
Appearantly you don't know the (input) frequency of the PLL when registering it to the framework, so the question must be: What's wrong with keeping it uninitialized?
Quoted 8 lines
If the PLL is unused then you don't care about it's initialization status. If it happens to be enabled by a bootloader and still unused at
late_initcalltime the clock framework will disable it so you have a known state then. If a consumer for the PLL appears it's its job to initialize it through the clk api.Sascha
Okay, what we need here is to initialize the PLL to a desired frequency, based on device tree settings (since it will be configured differently, among different boards). This is a PLL that 1) has limited options of frequencies which it can be configured to, and 2) has multiple child clocks, where is a more suitable place to initialize it to the desired frequency than right before registering it to the framework? I know a lot of people do it in the bootloader, but I thought we should be given the flexibility of configuring it in the kernel.
Quoted 5 lines
When you say "consumers", do you mean 1) the device driver that uses the PLL; or 2) the device driver that use the child clock of the PLL? If it's case 1), then we don't really have a device driver that directly uses the PLL, and I thought that's quite normal, as most PLLs don't directly feed into any peripherals.
Quoted 5 lines
I meant 1) and 2). Before a consumer comes along the state of the PLL doesn't matter. When a consumer shows up it has to call
clk_prepare_enablewhich (directly or indirectly) will enable your PLL. Then it's still time to apply the default settings you found out during probe of the PLL.
My review comments are really for iproc_pll_setup() in patch #3, but the discussion is here so I'll respond to this thread.
I think the root of this problem is that your pll clk_ops does not support .set_rate. That is why your clock driver hacks in a call to pll_set_rate in iproc_pll_setup.
Due to the above shortcoming you also do not use the assigned-clock-rate infrastructure to set your pll rate at registration-time. There is no reason for your driver to re-invent this logic. iproc_pll_setup is fetching the clock-frequency property from DT and then trying to set that rate. Instead please use the generic code.
The right way to handle this is to support a .set_rate callback (looks like you're 90% of the way there with pll_set_rate) and then use the assigned-clock-rates property to specify this from DT.
Regards,
Mike
Quoted 8 lines
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Ray Jui
maintainerRe: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Hi Mike,
Quoted 106 lines · Mike Turquette
Quoting Sascha Hauer (2015-02-26 00:43:19)
Quoted 86 lines · Ray Jui
Quoted 79 lines · Sascha Hauer
Quoted 16 lines · Ray Jui
Quoted 15 lines
Hi Sascha,
Quoted 12 lines · Sascha Hauer
Hi Ray,
Quoted 8 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case?
In the case when clock parent is not found, as you can see from the code, it simply returns zero, just like other clk get rate APIs.
Yes, but what do you do with the 0 result then in your PLL initialization?
As of the current code, it fails the PLL frequency initialization and bails out. Thinking about it more, it actually makes more sense to just warn and still go ahead to register the clock, in which case it will use whatever default frequency after chip power on reset or a frequency configured in the bootloader.
Quoted 6 lines
Quoted 5 lines
I thought the order of clock registration is based on order of the clock nodes in device tree. It makes sense to me to declare the parent clock before a child clock, so it's guaranteed that the parent is registered before the child.
Quoted 6 lines
No, you can't rely on that. The order of the device nodes may happen to define the order of clock initialization now, but that may change. device nodes are usually ordered by bus addresses, not by intended initialization order. Even if you reorder them everything must still work.
Okay I get your point that the order of device nodes may not be relied on for device initialization order. But then another mechanism should be deployed to give developers the option to decide on the clock initialization sequence. It can be optional but it should be there.
Quoted 11 lines
Quoted 6 lines
Quoted 3 lines
Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sure it's not mandatory. But what's wrong with me choosing to initialize the PLL clock to a known frequency before registering it to the framework?
Appearantly you don't know the (input) frequency of the PLL when registering it to the framework, so the question must be: What's wrong with keeping it uninitialized?
Quoted 8 lines
If the PLL is unused then you don't care about it's initialization status. If it happens to be enabled by a bootloader and still unused at
late_initcalltime the clock framework will disable it so you have a known state then. If a consumer for the PLL appears it's its job to initialize it through the clk api.Sascha
Okay, what we need here is to initialize the PLL to a desired frequency, based on device tree settings (since it will be configured differently, among different boards). This is a PLL that 1) has limited options of frequencies which it can be configured to, and 2) has multiple child clocks, where is a more suitable place to initialize it to the desired frequency than right before registering it to the framework? I know a lot of people do it in the bootloader, but I thought we should be given the flexibility of configuring it in the kernel.
Quoted 5 lines
When you say "consumers", do you mean 1) the device driver that uses the PLL; or 2) the device driver that use the child clock of the PLL? If it's case 1), then we don't really have a device driver that directly uses the PLL, and I thought that's quite normal, as most PLLs don't directly feed into any peripherals.
Quoted 5 lines
I meant 1) and 2). Before a consumer comes along the state of the PLL doesn't matter. When a consumer shows up it has to call
clk_prepare_enablewhich (directly or indirectly) will enable your PLL. Then it's still time to apply the default settings you found out during probe of the PLL.My review comments are really for
iproc_pll_setup()in patch #3, but the discussion is here so I'll respond to this thread.I think the root of this problem is that your pll
clk_opsdoes not support .set_rate. That is why your clock driver hacks in a call topll_set_rateiniproc_pll_setup.Due to the above shortcoming you also do not use the assigned-clock-rate infrastructure to set your pll rate at registration-time. There is no reason for your driver to re-invent this logic.
iproc_pll_setupis fetching the clock-frequency property from DT and then trying to set that rate. Instead please use the generic code.
Quoted 7 lines
The right way to handle this is to support a .set_rate callback (looks like you're 90% of the way there with
pll_set_rate) and then use the assigned-clock-rates property to specify this from DT.Regards,
Mike
Okay. It's good to know that "assigned-clock-rate" can be used and serve exactly what we need here. I'll update my patch series to use that instead.
In this case, do you think I should still keep of_clk_get_parent_rate in the patch series?
Thanks,
Ray
Quoted 8 lines
Quoted 8 lines
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Re: [PATCH v5 1/6] clk: add of_clk_get_parent_rate function
Quoting Ray Jui (2015-03-06 12:07:13)
Quoted 117 lines
Hi Mike,
Quoted 106 lines · Mike Turquette
Quoting Sascha Hauer (2015-02-26 00:43:19)
Quoted 86 lines · Ray Jui
Quoted 79 lines · Sascha Hauer
Quoted 16 lines · Ray Jui
Quoted 15 lines
Hi Sascha,
Quoted 12 lines · Sascha Hauer
Hi Ray,
Quoted 8 lines · Ray Jui
Sometimes a clock needs to know the rate of its parent before itself is registered to the framework. An example is that a PLL may need to initialize itself to a specific VCO frequency, before registering to the framework. The parent rate needs to be known, for PLL multipliers and divisors to be configured properly.
Introduce helper function
of_clk_get_parent_rate, which can be used to obtain the parent rate of a clock, given a device node and index.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
I can't see how this patch helps you. First it's not guaranteed that the parent is already registered, what do you do in this case?
In the case when clock parent is not found, as you can see from the code, it simply returns zero, just like other clk get rate APIs.
Yes, but what do you do with the 0 result then in your PLL initialization?
As of the current code, it fails the PLL frequency initialization and bails out. Thinking about it more, it actually makes more sense to just warn and still go ahead to register the clock, in which case it will use whatever default frequency after chip power on reset or a frequency configured in the bootloader.
Quoted 6 lines
Quoted 5 lines
I thought the order of clock registration is based on order of the clock nodes in device tree. It makes sense to me to declare the parent clock before a child clock, so it's guaranteed that the parent is registered before the child.
Quoted 6 lines
No, you can't rely on that. The order of the device nodes may happen to define the order of clock initialization now, but that may change. device nodes are usually ordered by bus addresses, not by intended initialization order. Even if you reorder them everything must still work.
Okay I get your point that the order of device nodes may not be relied on for device initialization order. But then another mechanism should be deployed to give developers the option to decide on the clock initialization sequence. It can be optional but it should be there.
Quoted 11 lines
Quoted 6 lines
Quoted 3 lines
Then the clock framework doesn't require that you initialize the PLL before registering. That can be done in the clk ops later.
Sure it's not mandatory. But what's wrong with me choosing to initialize the PLL clock to a known frequency before registering it to the framework?
Appearantly you don't know the (input) frequency of the PLL when registering it to the framework, so the question must be: What's wrong with keeping it uninitialized?
Quoted 8 lines
If the PLL is unused then you don't care about it's initialization status. If it happens to be enabled by a bootloader and still unused at
late_initcalltime the clock framework will disable it so you have a known state then. If a consumer for the PLL appears it's its job to initialize it through the clk api.Sascha
Okay, what we need here is to initialize the PLL to a desired frequency, based on device tree settings (since it will be configured differently, among different boards). This is a PLL that 1) has limited options of frequencies which it can be configured to, and 2) has multiple child clocks, where is a more suitable place to initialize it to the desired frequency than right before registering it to the framework? I know a lot of people do it in the bootloader, but I thought we should be given the flexibility of configuring it in the kernel.
Quoted 5 lines
When you say "consumers", do you mean 1) the device driver that uses the PLL; or 2) the device driver that use the child clock of the PLL? If it's case 1), then we don't really have a device driver that directly uses the PLL, and I thought that's quite normal, as most PLLs don't directly feed into any peripherals.
Quoted 5 lines
I meant 1) and 2). Before a consumer comes along the state of the PLL doesn't matter. When a consumer shows up it has to call
clk_prepare_enablewhich (directly or indirectly) will enable your PLL. Then it's still time to apply the default settings you found out during probe of the PLL.My review comments are really for
iproc_pll_setup()in patch #3, but the discussion is here so I'll respond to this thread.I think the root of this problem is that your pll
clk_opsdoes not support .set_rate. That is why your clock driver hacks in a call topll_set_rateiniproc_pll_setup.Due to the above shortcoming you also do not use the assigned-clock-rate infrastructure to set your pll rate at registration-time. There is no reason for your driver to re-invent this logic.
iproc_pll_setupis fetching the clock-frequency property from DT and then trying to set that rate. Instead please use the generic code.Quoted 7 lines
The right way to handle this is to support a .set_rate callback (looks like you're 90% of the way there with
pll_set_rate) and then use the assigned-clock-rates property to specify this from DT.Regards,
Mike
Quoted 5 lines
Okay. It's good to know that "assigned-clock-rate" can be used and serve exactly what we need here. I'll update my patch series to use that instead.
In this case, do you think I should still keep
of_clk_get_parent_ratein the patch series?
No. Without a user we should drop it, and I also do not like its use of clk_lookup.
Thanks,
Mike
Quoted 13 lines
Thanks,
Ray
Quoted 8 lines
Quoted 8 lines
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Ray Jui
maintainerPATCH v5 2/6 clk: iproc: define Broadcom iProc clock binding
In reply to Ray JuiDocument the device tree binding for Broadcom iProc architecture based clock controller
--- brcm,iproc-clocks.txt | 178 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 brcm,iproc-clocks.txt
brcm,iproc-clocks.txt new file +178 -0
@@ -0,0 +1,178 @@ +Broadcom iProc Family Clocks + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +The iProc clock controller manages clocks that are common to the iProc family. +An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL, +LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL +comprises of several leaf clocks + +Required properties for PLLs: +- compatible: + Should have a value of the form "brcm,<soc>-<pll>". For example, GENPLL on +Cygnus has a compatible string of "brcm,cygnus-genpll" + +- #clock-cells: + Must be <0> + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL + +- clocks: + The input parent clock phandle for the PLL. For all iProc PLLs, this is an +onboard crystal with a fixed rate + +Optional Properties for PLLs: +- clock-frequency: + PLL frequency in Hz. If specified, PLL will be configured to run at +<clock-frequency> instead of the default frequency after chip reset, provided +that <clock-frequency> and its parameters are defined in the SoC specific +frequency parameter table + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + +Required properties for leaf clocks of a PLL: + +- compatible: + Should have a value of the form "brcm,<soc>-<pll>-clk". For example, leaf +clocks derived from the GENPLL on Cygnus SoC have a compatible string of +"brcm,cygnus-genpll-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 leaf clock of a +given PLL + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL leaf clocks + +- clocks: + The input parent PLL phandle for the leaf clock + +- clock-output-names: + An ordered list of strings defining the names of the leaf clocks + +Example: + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + +Required properties for ASIU clocks: + +ASIU clocks are a special case. These clocks are derived directly from the +reference clock of the onboard crystal + +- compatible: + Should have a value of the form "brcm,<soc>-asiu-clk". For example, ASIU +clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 ASIU clocks + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for ASIU clocks + +- clocks: + The input parent clock phandle for the ASIU clock, i.e., the onboard +crystal + +- clock-output-names: + An ordered list of strings defining the names of the ASIU clocks + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; + }; + +Cygnus +------ +PLL and leaf clock compatible strings for Cygnus are: + "brcm,cygnus-armpll" + "brcm,cygnus-genpll" + "brcm,cygnus-lcpll0" + "brcm,cygnus-mipipll" + "brcm,cygnus-genpll-clk" + "brcm,cygnus-lcpll0-clk" + "brcm,cygnus-mipipll-clk" + "brcm,cygnus-asiu-clk" + +The following table defines the set of PLL/clock index and ID for Cygnus. +These clock IDs are defined in: + "include/dt-bindings/clock/bcm-cygnus.h" + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + armpll crystal N/A N/A + genpll crystal N/A N/A + lcpll0 crystal N/A N/A + mipipll crystal N/A N/A + + keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK + adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK + pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK + + axi21 genpll 0 BCM_CYGNUS_GENPLL_AXI21_CLK + 250mhz genpll 1 BCM_CYGNUS_GENPLL_250MHZ_CLK + ihost_sys genpll 2 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK + enet_sw genpll 3 BCM_CYGNUS_GENPLL_ENET_SW_CLK + audio_125 genpll 4 BCM_CYGNUS_GENPLL_AUDIO_125_CLK + can genpll 5 BCM_CYGNUS_GENPLL_CAN_CLK + + pcie_phy lcpll0 0 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK + ddr_phy lcpll0 1 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK + sdio lcpll0 2 BCM_CYGNUS_LCPLL0_SDIO_CLK + usb_phy lcpll0 3 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK + smart_card lcpll0 4 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK + ch5 lcpll0 5 BCM_CYGNUS_LCPLL0_CH5_UNUSED + + ch0_unused mipipll 0 BCM_CYGNUS_MIPIPLL_CH0_UNUSED + ch1_lcd mipipll 1 BCM_CYGNUS_MIPIPLL_CH1_LCD + ch2_unused mipipll 2 BCM_CYGNUS_MIPIPLL_CH2_UNUSED + ch3_unused mipipll 3 BCM_CYGNUS_MIPIPLL_CH3_UNUSED + ch4_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH4_UNUSED + ch5_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH5_UNUSED
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 3/6 clk: iproc: add initial common clock support
In reply to Ray JuiThis adds basic and generic support for various iProc PLLs and clocks including the ARMPLL, GENPLL, LCPLL, MIPIPLL, and ASIU clocks.
SoCs under the iProc architecture can define their specific register offsets and clock parameters for their PLL and clock controllers. These parameters can be passed as arugments into the generic iProc PLL and clock setup functions
Derived from code originally provided by Jonathan Richardson <[email protected]>
--- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-iproc-armpll.c | 282 ++++++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 +++++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 +++++++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 461 ++++++++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 157 ++++++++++++ 7 files changed, 1423 insertions(+) create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h
drivers/clk/bcm/Kconfig +9 -0
@@ -7,3 +7,12 @@ config CLK_BCM_KONA Enable common clock framework support for Broadcom SoCs using "Kona" style clock control units, including those in the BCM281xx and BCM21664 families. + +config COMMON_CLK_IPROC + bool "Broadcom iProc clock support" + depends on ARCH_BCM_IPROC + depends on COMMON_CLK + default y + help + Enable common clock framework support for Broadcom SoCs + based on the "iProc" architecture
drivers/clk/bcm/Makefile +1 -0
@@ -2,3 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o +obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o
drivers/clk/bcm/clk-iproc-armpll.c new file +282 -0
282 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-asiu.c new file +275 -0
275 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-clk.c new file +238 -0
238 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-pll.c new file +461 -0
461 lines not on this page · raw message
drivers/clk/bcm/clk-iproc.h new file +157 -0
157 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 4/6 clk: Change bcm clocks build dependency
In reply to Ray JuiThe clock code under drivers/clk/bcm now contains code for both the Broadcom mobile SoCs and the iProc SoCs. Change the the makefile dependency to be under config flag CONFIG_ARCH_BCM that's enabled for both families of SoCs
--- drivers/clk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/Makefile +1 -1
@@ -41,7 +41,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ -obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ +obj-$(CONFIG_ARCH_BCM) += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HIP04) += hisilicon/
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 5/6 clk: cygnus: add clock support for Broadcom Cygnus
In reply to Ray JuiThe Broadcom Cygnus SoC is architected under the iProc architecture. It has the following PLLs: ARMPLL, GENPLL, LCPLL0, MIPIPLL, all dervied from an onboard crystal. Cygnus also has various ASIU clocks that are derived directly from the onboard crystal.
--- drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-cygnus.c | 277 ++++++++++++++++++++++++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 65 ++++++++ 3 files changed, 343 insertions(+) create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
drivers/clk/bcm/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o +obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
drivers/clk/bcm/clk-cygnus.c new file +277 -0
277 lines not on this page · raw message
include/dt-bindings/clock/bcm-cygnus.h new file +65 -0
65 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 6/6 ARM: dts: enable clock support for Broadcom Cygnus
In reply to Ray JuiReplace current device tree dummy clocks with real clock support for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 ++++++++++++++++++++++++------- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- 2 files changed, 86 insertions(+), 26 deletions(-)
arch/arm/boot/dts/bcm-cygnus-clock.dtsi +85 -25
@@ -36,56 +36,116 @@ clocks { ranges; osc: oscillator { + #clock-cells = <0>; compatible = "fixed-clock"; - #clock-cells = <1>; clock-frequency = <25000000>; }; - apb_clk: apb_clk { - compatible = "fixed-clock"; + /* Cygnus ARM PLL */ + armpll: armpll { #clock-cells = <0>; - clock-frequency = <1000000000>; + compatible = "brcm,cygnus-armpll"; + clocks = <&osc>; + reg = <0x19000000 0x1000>; }; - periph_clk: periph_clk { - compatible = "fixed-clock"; + /* peripheral clock for system timer */ + arm_periph_clk: arm_periph_clk { #clock-cells = <0>; - clock-frequency = <500000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <2>; + clock-mult = <1>; }; - sdio_clk: lcpll_ch2 { - compatible = "fixed-clock"; + /* APB bus clock */ + apb_clk: apb_clk { #clock-cells = <0>; - clock-frequency = <200000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <4>; + clock-mult = <1>; }; - axi81_clk: axi81_clk { - compatible = "fixed-clock"; + genpll: genpll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - keypad_clk: keypad_clk { - compatible = "fixed-clock"; + /* various clocks running off the GENPLL */ + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + + /* always 1/2 of the axi21 clock */ + axi41_clk: axi41_clk { #clock-cells = <0>; - clock-frequency = <31806>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <2>; + clock-mult = <1>; }; - adc_clk: adc_clk { - compatible = "fixed-clock"; + /* always 1/4 of the axi21 clock */ + axi81_clk: axi81_clk { #clock-cells = <0>; - clock-frequency = <1562500>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <4>; + clock-mult = <1>; }; - pwm_clk: pwm_clk { - compatible = "fixed-clock"; + lcpll0: lcpll0 { #clock-cells = <0>; - clock-frequency = <1000000>; + compatible = "brcm,cygnus-lcpll0"; + reg = <0x0301d02c 0x1c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - lcd_clk: mipipll_ch1 { - compatible = "fixed-clock"; + /* various clocks running off the LCPLL0 */ + lcpll0_clks: lcpll0_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-lcpll0-clk"; + reg = <0x0301d02c 0x1c>; + clocks = <&lcpll0>; + clock-output-names = "pcie_phy", "ddr_phy", "sdio", + "usb_phy", "smart_card", "ch5"; + }; + + mipipll: mipipll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-mipipll"; + reg = <0x180a9800 0x2c>, + <0x0301c020 0x4>, + <0x180aa024 0x4>; + clock-frequency = <2100000000>; + clocks = <&osc>; + }; + + mipipll_clks: mipipll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-mipipll-clk"; + reg = <0x180a9800 0x2c>; + clocks = <&mipipll>; + clock-output-names = "ch0_unused", "ch1_lcd", "ch2_unused", + "ch3_unused", "ch4_unused", "ch5_unused"; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; }; };
arch/arm/boot/dts/bcm-cygnus.dtsi +1 -1
@@ -134,7 +134,7 @@ compatible = "arm,cortex-a9-global-timer"; reg = <0x19020200 0x100>; interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&periph_clk>; + clocks = <&arm_periph_clk>; }; };
Signature · 1 line
1.7.9.5
Re: [PATCH v5 0/6] Add common clock support for Broadcom iProc architecture
In reply to Ray JuiQuoted 25 lines · Ray Jui
This patchset contains the initial common clock support for Broadcom's iProc family of SoCs. The iProc clock architecture comprises of various PLLs, e.g., ARMPLL, GENPLL, LCPLL0, MIPIPLL, and etc. An onboard crystal serves as the basic reference clock for these PLLs. Each PLL may have several leaf clocks. One special group of clocks is the ASIU clocks, which are dervied directly from the crystal reference clock.
This patchset also contains the basic clock support for the Broadcom Cygnus SoC, which implements the iProc clock architecture
Changes from v4:
- Addof_clk_get_parent_ratehelper function into the clock framework
- Switch to useof_clk_get_parent_ratein the iProc PLL clock driverChanges from v3:
- Fix incorrect use of passing inof_clk_src_onecell_getwhen adding ARM PLL and other iProc PLLs as clock provider. These PLLs have zero cells in DT and theforeof_clk_src_simple_getshould be used instead
- Rename Cygnus MIPI PLL Channel 2 clock fromBCM_CYGNUS_MIPIPLL_CH2_UNUSEDtoBCM_CYGNUS_MIPIPLL_CH2_V3D, since a 3D graphic rendering engine has been integrated into Cygnus revision B0 and has its core clock running off MIPI PLL Channel 2
- Changed default MIPI PLL VCO frequency from 1.75 GHz to 2.1 GHz. This allows us to derive 300 MHz V3D clock from channel 2 through the post divisor
Quoted 8 lines
Changes from v2:
- Re-arrange Cygnus clock/pll init functions so each init function is right next to its clock table
- Removed #defines for number of clocks in Cygnus. Have the number of clocks automatically determined based on array size of the clock tableChanges from v1:
- Separatedrivers/clk/Makefilechange fordrivers/clk/bcmout to a standalone patch
FWIW I tested this series on BCM958305K SVK.
Thanks.
Signature · 1 line
Dmitry
Ray Jui
maintainerv8 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Changes from v7:
- Remove redundant 10-bit address check in the driver
- Fix the driver that accidentally emits 1-byte of data with zero content in the case of SMBUS quick command
- Improve debugging prints in the driver
- Other minor improvements
Changes from v6:
- Get rid of unnecessary atomic variable usage in the driver
- Improve the "waiting for transaction to complete" logic further by making sure there's no pending/ongoing interrupt by the time when flag 'xfer_is_done' is checked
- After disabling interrupt with 'writel', add 'readl' to the same register to flush the bus to ensure the write has gone through
Changes from v5:
- Improve the "waiting for transaction to be complete" logic to take care of the corner case when an interrupt fires after wait_for_completion_timeout times out
- Improve the logic to disable I2C interrupt in the remove function. Make it more generic so it works for both dedicated and shared interrupt
Changes from v4:
- Remove redundant header file includes
- Change the logic that waits for the host controller to be idle to simply return -EBUSY
- Use proper print level and error codes in the driver
- Allow zero length message in the driver to support I2C_SMBUS_QUICK
- Change back to use devm_request_irq. Disable interrupt in the remove function so there's no outstanding I2C interrupt when the driver is being removed from the framework
- Other minor miscellaneous improvements and fixes
Changes from v3:
- Add config dependency to COMPILE_TEST to allow the driver to be build tested by other platforms
- Improve CPU utilization efficiency in the loop of waiting for bus to idle
- Add more comment in the driver to clarify the way how the "start busy" interrupt is triggered from the I2C controller
- Fix inconsistent coding style and format
- Improve the bus speed validation logic in the driver
- Add code to free the interrupt line in driver's remove function. Also change to use non-devm API to request the interrupt line
- Other miscellaneous improvements and fixes
Changes from v2:
- Have the I2C driver default to y so it does not need to be selected from ARCH_BCM_IPROC. This also helps to get rid of one patch. The driver still depends on ARCH_BCM_IPROC
- Get rid of redundant check on resource returned by platform_get_resource
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (3):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 494 ++++++++++++++++++++ 5 files changed, 562 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v8 1/3 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v8 2/3 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 494 ++++++++++++++++++++++++++++++++++++ 3 files changed, 505 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +10 -0
@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +494 -0
494 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v8 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hi Ray,
Quoted 6 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Mostly looking good.
drivers/i2c/busses/i2c-bcm-iproc.c line 21
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h>
Please sort the includes.
drivers/i2c/busses/i2c-bcm-iproc.c line 128
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+static bool bcm_iproc_i2c_bus_busy (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +if (readl (iproc_i2c->base +M_CMD_OFFSET ) & + (1 <<M_CMD_START_BUSY_SHIFT )) +return true; +else +return false; +}
Minor: return !!(readl(...))? You decide.
drivers/i2c/busses/i2c-bcm-iproc.c line 139
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+ +static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg,u8 *addr) +{ + *addr = msg->addr <<1 ; + +if (msg->flags &I2C_M_RD ) + *addr |=1 ; + +return 0 ; +}
I'd suggest a oneliner.
*addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0)
Or use !! like above.
Don't do an extra function for that. It is only used once and it also doesn't need to be int since it can't fail anyhow.
(Note to self: I should make a macro for that in i2c.h)
drivers/i2c/busses/i2c-bcm-iproc.c line 188
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+/* need to reserve one byte in the FIFO for the slave address */ +if (msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (iproc_i2c->device, +"only support data length up to %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ;
-EOPNOTSUPP
Is it really a HW limitation? Could the driver later be extended to continue filling the FIFO if a certain threshold is reached?
drivers/i2c/busses/i2c-bcm-iproc.c line 283
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+dev_dbg (iproc_i2c->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (iproc_i2c->device,"*** data: %*ph\n" , msg->len, msg->buf);
Not really needed. We have tracing for that.
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+if (bus_speed <100000 ) { +dev_err (iproc_i2c->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (iproc_i2c->device, +"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + }else if (bus_speed <400000 ) {
drivers/i2c/busses/i2c-bcm-iproc.c line 344
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ bus_speed =100000 ; + speed_bit =0 ; + }else { + bus_speed =400000 ; + speed_bit =1 ; + } + + val =readl (iproc_i2c->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIM_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIM_CFG_MODE_400_SHIFT ;
val |= (bus_speed == 400000) ...
and skip speed_bit? You decide.
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + + val =readl (iproc_i2c->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, iproc_i2c->base +CFG_OFFSET );
drivers/i2c/busses/i2c-bcm-iproc.c line 398
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + + val =readl (iproc_i2c->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); +}
Extra functions? They are self explaining and only used once. You decide.
Rest looks fine, thanks!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150207/e4a4fb2e/attachment-0001.sig>
Ray Jui
maintainerRe: [PATCH v8 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 12 lines · Wolfram Sang
Hi Ray,
Quoted 6 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Mostly looking good.
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 21
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> Please sort the includes.
Will do.
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 128
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+static bool bcm_iproc_i2c_bus_busy (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +if (readl (iproc_i2c->base +M_CMD_OFFSET ) & + (1 <<M_CMD_START_BUSY_SHIFT )) +return true; +else +return false; +}Minor: return !!(readl(...))? You decide.
Okay will do that. Will also remove this function since now it becomes one line and is used only once.
Quoted 14 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 139
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+ +static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg,u8 *addr) +{ + *addr = msg->addr <<1 ; + +if (msg->flags &I2C_M_RD ) + *addr |=1 ; + +return 0 ; +}I'd suggest a oneliner.
Quoted 9 lines
*addr =
msg->addr<< 1 | (msg->flags&I2C_M_RD? 1 : 0)Or use !! like above.
Don't do an extra function for that. It is only used once and it also doesn't need to be int since it can't fail anyhow.
(Note to self: I should make a macro for that in
i2c.h)
Yes will change. Thanks.
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 188
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+/* need to reserve one byte in the FIFO for the slave address */ +if (msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (iproc_i2c->device, +"only support data length up to %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ;
-EOPNOTSUPP
Quoted 3 lines
Is it really a HW limitation? Could the driver later be extended to continue filling the FIFO if a certain threshold is reached?
Will return -EOPNOTSUPP. This really depends on whether or not we expect one sequence of START + SLV ADDR + DATA + STOP per i2c message. I can later extend the driver to refill/re-drain the FIFO for data size >= 64 bytes, if one sequence of SATRT...STOP per message is not a requirement.
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 283
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+dev_dbg (iproc_i2c->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (iproc_i2c->device,"*** data: %*ph\n" , msg->len, msg->buf);Not really needed. We have tracing for that.
Will remove.
Quoted 20 lines
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+if (bus_speed <100000 ) { +dev_err (iproc_i2c->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (iproc_i2c->device, +"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + }else if (bus_speed <400000 ) {drivers/i2c/busses/i2c-bcm-iproc.c line 344
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ bus_speed =100000 ; + speed_bit =0 ; + }else { + bus_speed =400000 ; + speed_bit =1 ; + } + + val =readl (iproc_i2c->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIM_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIM_CFG_MODE_400_SHIFT ;val |= (
bus_speed== 400000) ...
Quoted 2 lines
and skip
speed_bit? You decide.
Okay, I'll get rid of speed_bit.
Quoted 12 lines
Quoted 12 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +12
-0+static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + + val =readl (iproc_i2c->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, iproc_i2c->base +CFG_OFFSET ); +} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val;
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 380
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+ + val =readl (iproc_i2c->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); +}Extra functions? They are self explaining and only used once. You decide.
In fact I'll keep the function, since it will likely be needed later when we add suspend/resume support to the driver. But I'll combine the two functions and make it a single function called bcm_iproc_i2c_enable_disable.
Quoted 3 lines
Rest looks fine, thanks!
Thanks for the review!
Ray
Re: [PATCH v8 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 9 lines
Quoted 4 lines
Is it really a HW limitation? Could the driver later be extended to continue filling the FIFO if a certain threshold is reached?
Will return
-EOPNOTSUPP. This really depends on whether or not we expect one sequence of START + SLV ADDR + DATA + STOP per i2c message. I can later extend the driver to refill/re-drain the FIFO for data size >= 64 bytes, if one sequence of SATRT...STOP per message is not a requirement.
It is important to have the terminology clear here: One transfer can consist of multiple messages. The transfer uses START/STOP at the beginning/end, the messages within the transfer only REPEATED_START.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150208/14e75449/attachment.sig>
Ray Jui
maintainerRe: [PATCH v8 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 5 lines · Wolfram Sang
Quoted 5 lines
Quoted 4 lines
Is it really a HW limitation? Could the driver later be extended to continue filling the FIFO if a certain threshold is reached?
Quoted 9 lines
Quoted 4 lines
Will return
-EOPNOTSUPP. This really depends on whether or not we expect one sequence of START + SLV ADDR + DATA + STOP per i2c message. I can later extend the driver to refill/re-drain the FIFO for data size >= 64 bytes, if one sequence of SATRT...STOP per message is not a requirement.It is important to have the terminology clear here: One transfer can consist of multiple messages. The transfer uses START/STOP at the beginning/end, the messages within the transfer only
REPEATED_START.
Okay. Let me check with our ASIC engineer to see if there's a way to get the driver extended to support the case when data size is larger than the FIFO size. From my understanding based on the data sheet I have, I don't think that can be done with this controller. But if the ASIC engineers tells me the opposite, I'll add it as a separate patch later.
Thanks,
Ray
Re: [PATCH v8 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 6 lines
Okay. Let me check with our ASIC engineer to see if there's a way to get the driver extended to support the case when data size is larger than the FIFO size. From my understanding based on the data sheet I have, I don't think that can be done with this controller. But if the ASIC engineers tells me the opposite, I'll add it as a separate patch later.
Perfect, thanks!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150209/b20c9302/attachment.sig>
Ray Jui
maintainerPATCH v8 3/3 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv9 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Synced code base to Linux 3.19-rc7
Changes from v8:
- Sort header includes in alphabetical order
- Use correct error code
- Get rid of redundant functions and combine functions to make driver more slim
- Get rid of redundant debugging prints that are already available from the I2C framework
- Other minor improvements
Changes from v7:
- Remove redundant 10-bit address check in the driver
- Fix the driver that accidentally emits 1-byte of data with zero content in the case of SMBUS quick command
- Improve debugging prints in the driver
- Other minor improvements
Changes from v6:
- Get rid of unnecessary atomic variable usage in the driver
- Improve the "waiting for transaction to complete" logic further by making sure there's no pending/ongoing interrupt by the time when flag 'xfer_is_done' is checked
- After disabling interrupt with 'writel', add 'readl' to the same register to flush the bus to ensure the write has gone through
Changes from v5:
- Improve the "waiting for transaction to be complete" logic to take care of the corner case when an interrupt fires after wait_for_completion_timeout times out
- Improve the logic to disable I2C interrupt in the remove function. Make it more generic so it works for both dedicated and shared interrupt
Changes from v4:
- Remove redundant header file includes
- Change the logic that waits for the host controller to be idle to simply return -EBUSY
- Use proper print level and error codes in the driver
- Allow zero length message in the driver to support I2C_SMBUS_QUICK
- Change back to use devm_request_irq. Disable interrupt in the remove function so there's no outstanding I2C interrupt when the driver is being removed from the framework
- Other minor miscellaneous improvements and fixes
Changes from v3:
- Add config dependency to COMPILE_TEST to allow the driver to be build tested by other platforms
- Improve CPU utilization efficiency in the loop of waiting for bus to idle
- Add more comment in the driver to clarify the way how the "start busy" interrupt is triggered from the I2C controller
- Fix inconsistent coding style and format
- Improve the bus speed validation logic in the driver
- Add code to free the interrupt line in driver's remove function. Also change to use non-devm API to request the interrupt line
- Other miscellaneous improvements and fixes
Changes from v2:
- Have the I2C driver default to y so it does not need to be selected from ARCH_BCM_IPROC. This also helps to get rid of one patch. The driver still depends on ARCH_BCM_IPROC
- Get rid of redundant check on resource returned by platform_get_resource
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (3):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 461 ++++++++++++++++++++ 5 files changed, 529 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v9 1/3 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Wolfram Sang
AppliedRe: [PATCH v9 1/3] i2c: iProc: define Broadcom iProc I2C binding
Quoted 6 lines · Ray Jui
Document the I2C device tree binding for Broadcom iProc family of SoCs
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>
Applied to for-next, thanks!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150209/f4265f58/attachment-0001.sig>
Ray Jui
maintainerPATCH v9 2/3 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 461 ++++++++++++++++++++++++++++++++++++ 3 files changed, 472 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +10 -0
@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +461 -0
461 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v9 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 10 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>
Looks good. What kind of tests have you done with exactly this version of the driver (not earlier ones)?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150208/15f140da/attachment.sig>
Ray Jui
maintainerRe: [PATCH v9 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 8 lines · Wolfram Sang
Quoted 7 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Quoted 7 lines
Quoted 3 lines
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>Looks good. What kind of tests have you done with exactly this version of the driver (not earlier ones)?
I did build test and ran i2cdetect on Cygnus BCM958300K combo board with the 3.19 rc7 kernel, and then I back ported this driver to our 3.10 version of the production kernel (where we have complete audio driver support), to run some audio playback tests, which involves using the wolfson codec (through i2c). The only line I added when back porting to the 3.10 kernel is of_i2c_register_devices at the end of probe.
Thanks,
Ray
Wolfram Sang
AppliedRe: [PATCH v9 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiQuoted 10 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>
Applied to for-next, thanks!
Next time, please send new patches as seperate threads, not as a reply to the old series.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150209/ede3c1de/attachment.sig>
Ray Jui
maintainerRe: [PATCH v9 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 8 lines · Wolfram Sang
Quoted 7 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Quoted 9 lines
Quoted 3 lines
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>Applied to for-next, thanks!
Next time, please send new patches as seperate threads, not as a reply to the old series.
Thanks, Wolfram. I think I'm missing something here and would like to get it clarified, so I don't make the same mistake again in the future:
I thought I've already sent these patches as a new thread, i.e., [PATCH v9 ...], isn't it?
Thanks,
Ray
Re: [PATCH v9 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 5 lines
Thanks, Wolfram. I think I'm missing something here and would like to get it clarified, so I don't make the same mistake again in the future:
I thought I've already sent these patches as a new thread, i.e., [PATCH v9 ...], isn't it?
Yes, but "In-Reply-To" was set and so my MUAs (mutt and Thunderbird) threaded them to your first submission. Most people I know prefer to have this not threaded.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150210/05111ede/attachment.sig>
Ray Jui
maintainerRe: [PATCH v9 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 10 lines · Wolfram Sang
Quoted 5 lines
Thanks, Wolfram. I think I'm missing something here and would like to get it clarified, so I don't make the same mistake again in the future:
I thought I've already sent these patches as a new thread, i.e., [PATCH v9 ...], isn't it?Yes, but "In-Reply-To" was set and so my MUAs (mutt and Thunderbird) threaded them to your first submission. Most people I know prefer to have this not threaded.
Okay I got it now. Thanks.
Ray
Ray Jui
maintainerPATCH v9 3/3 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Re: [PATCH v9 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Quoted 7 lines · Ray Jui
Add I2C device nodes and its properties in
bcm-cygnus.dtsibut keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the futureSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>
I usually don't take DTS patches. They should go via arm-soc. Please say so if there are reasons I should take them.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150209/c0a1ad9e/attachment.sig>
Ray Jui
maintainerRe: [PATCH v9 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Quoted 5 lines · Wolfram Sang
Quoted 4 lines · Ray Jui
Add I2C device nodes and its properties in
bcm-cygnus.dtsibut keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
Quoted 7 lines
Quoted 3 lines
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>I usually don't take DTS patches. They should go via arm-soc. Please say so if there are reasons I should take them.
Okay. I'll send this as an individual patch to arm-soc.
Thanks,
Ray
Re: [PATCH v9 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Le 09/02/2015 21:24, Ray Jui a ?crit :
Quoted 8 lines · Wolfram Sang
Quoted 5 lines · Ray Jui
Quoted 4 lines
Add I2C device nodes and its properties in
bcm-cygnus.dtsibut keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>I usually don't take DTS patches. They should go via arm-soc. Please say so if there are reasons I should take them.
Okay. I'll send this as an individual patch to arm-soc.
Could you put in in a branch somewhere on github.com?/cygnus-linus.git so it's easy for me to pull from there?
--
Florian
Ray Jui
maintainerRe: [PATCH v9 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Quoted 16 lines · Florian Fainelli
Le 09/02/2015 21:24, Ray Jui a ?crit :
Quoted 15 lines · Wolfram Sang
Quoted 12 lines · Ray Jui
Quoted 7 lines
Add I2C device nodes and its properties in
bcm-cygnus.dtsibut keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the futureSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>Reviewed-by Kevin Cernekee <[email protected]>I usually don't take DTS patches. They should go via arm-soc. Please say so if there are reasons I should take them.
Quoted 7 lines
Quoted 1 line
Okay. I'll send this as an individual patch to arm-soc.
Could you put in in a branch somewhere on github.com?/cygnus-linus.git so it's easy for me to pull from there?
--
Florian
Hi Florian,
It's in branch cygnus-i2c-v9.
Thanks!
Ray