diff mbox

[2/4] pinctrl: cygnus: add initial pinctrl support

Message ID 1417131990-17954-3-git-send-email-rjui@broadcom.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ray Jui Nov. 27, 2014, 11:46 p.m. UTC
This adds the initial driver support for the Broadcom Cygnus pinctrl
controller. The Cygnus pinctrl controller supports group based
alternate function configuration

Signed-off-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---
 drivers/pinctrl/Kconfig              |    7 +
 drivers/pinctrl/Makefile             |    1 +
 drivers/pinctrl/pinctrl-bcm-cygnus.c |  753 ++++++++++++++++++++++++++++++++++
 3 files changed, 761 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-bcm-cygnus.c

Comments

Linus Walleij Jan. 9, 2015, 11:03 a.m. UTC | #1
On Fri, Nov 28, 2014 at 12:46 AM, Ray Jui <rjui@broadcom.com> wrote:

> This adds the initial driver support for the Broadcom Cygnus pinctrl
> controller. The Cygnus pinctrl controller supports group based
> alternate function configuration
>
> Signed-off-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
> ---
>  drivers/pinctrl/Kconfig              |    7 +
>  drivers/pinctrl/Makefile             |    1 +
>  drivers/pinctrl/pinctrl-bcm-cygnus.c |  753 ++++++++++++++++++++++++++++++++++

With the proliferation of Broadcom drivers, please first send a
patch moving pinctrl-bcm281xx.c and pinctrl-bcm2835.c to
drivers/pinctrl/broadcom or something, so we can collect them
there.

I don't know if the hardware has any similarity though, so invite
the authors of the previous drivers to review this code.

> +config PINCTRL_BCM_CYGNUS
> +       bool "Broadcom Cygnus pinctrl driver"
> +       depends on (ARCH_BCM_CYGNUS || COMPILE_TEST)
> +       select PINMUX
> +       select PINCONF
> +       select GENERIC_PINCONF

Nice that you use GENERIC_PINCONF! :)

> +/*
> + * Cygnus pinctrl core
> + *
> + * @pctl: pointer to pinctrl_dev
> + * @dev: pointer to the device
> + * @base: I/O register base for Cygnus pinctrl configuration
> + *
> + */
> +struct cygnus_pinctrl {
> +       struct pinctrl_dev *pctl;
> +       struct device *dev;
> +       void __iomem *base;
> +
> +       const struct pinctrl_pin_desc *pins;
> +       unsigned num_pins;

Why is this not simply just a part of struct pinctrl_desc?
Why does it have to be multiplied here?

> +/*
> + * List of groups of pins
> + */
> +static const unsigned gpio0_pins[] = { 12 };
> +static const unsigned gpio1_pins[] = { 13 };
> +static const unsigned gpio2_pins[] = { 14 };
> +static const unsigned gpio3_pins[] = { 15 };
> +static const unsigned gpio4_pins[] = { 16 };
> +static const unsigned gpio5_pins[] = { 17 };
> +static const unsigned gpio6_pins[] = { 18 };
> +static const unsigned gpio7_pins[] = { 19 };
> +static const unsigned gpio8_pins[] = { 20 };
> +static const unsigned gpio9_pins[] = { 21 };
> +static const unsigned gpio10_pins[] = { 22 };
> +static const unsigned gpio11_pins[] = { 23 };
> +static const unsigned gpio12_pins[] = { 24 };
> +static const unsigned gpio13_pins[] = { 25 };
> +static const unsigned gpio14_pins[] = { 26 };
> +static const unsigned gpio15_pins[] = { 27 };
> +static const unsigned gpio16_pins[] = { 28 };
> +static const unsigned gpio17_pins[] = { 29 };
> +static const unsigned gpio18_pins[] = { 30 };
> +static const unsigned gpio19_pins[] = { 31 };
> +static const unsigned gpio20_pins[] = { 32 };
> +static const unsigned gpio21_pins[] = { 33 };
> +static const unsigned gpio22_pins[] = { 34 };
> +static const unsigned gpio23_pins[] = { 35 };

Have you considered implementing .gpio_request_enable()
and .gpio_disable_free() to get around having to have one
group for each GPIO line?

> +static const unsigned pwm0_pins[] = { 38 };
> +static const unsigned pwm1_pins[] = { 39 };
> +static const unsigned pwm2_pins[] = { 40 };
> +static const unsigned pwm3_pins[] = { 41 };
> +static const unsigned sdio0_pins[] = { 94, 95, 96, 97, 98, 99 };
> +static const unsigned smart_card0_pins[] = { 42, 43, 44, 46, 47 };
> +static const unsigned smart_card1_pins[] = { 48, 49, 50, 52, 53 };
> +static const unsigned spi0_pins[] = { 54, 55, 56, 57 };
> +static const unsigned spi1_pins[] = { 58, 59, 60, 61 };
> +static const unsigned spi2_pins[] = { 62, 63, 64, 65 };
> +static const unsigned spi3_pins[] = { 66, 67, 68, 69 };
> +static const unsigned d1w_pins[] = { 10, 11 };
> +static const unsigned lcd_pins[] = { 126, 127, 128, 129, 130, 131, 132,        133,
> +       134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
> +       148, 149, 150, 151, 152, 153, 154, 155 };
> +static const unsigned uart0_pins[] = { 70, 71, 72, 73 };
> +static const unsigned uart1_dte_pins[] = { 75, 76, 77, 78 };
> +static const unsigned uart1_pins[] = { 74, 79, 80, 81 };
> +static const unsigned uart3_pins[] = { 82, 83 };
> +static const unsigned qspi_pins[] = { 104, 105, 106, 107 };
> +static const unsigned nand_pins[] = { 110, 111, 112, 113, 114, 115, 116, 117,
> +       118, 119, 120, 121, 122, 123, 124, 125 };
> +static const unsigned sdio0_cd_pins[] = { 103 };
> +static const unsigned sdio0_mmc_pins[] = { 100, 101, 102 };
> +static const unsigned can0_spi4_pins[] = { 86, 87 };
> +static const unsigned can1_spi4_pins[] = { 88, 89 };
> +static const unsigned sdio1_cd_pins[] = { 93 };
> +static const unsigned sdio1_led_pins[] = { 84, 85 };
> +static const unsigned sdio1_mmc_pins[] = { 90, 91, 92 };
> +static const unsigned camera_led_pins[] = { 156, 157, 158, 159, 160 };
> +static const unsigned camera_rgmii_pins[] = { 169, 170, 171, 169, 170, 171,
> +       172, 173 };
> +static const unsigned camera_sram_rgmii_pins[] = { 161, 162, 163, 164, 165,
> +       166, 167, 168 };
> +static const unsigned qspi_gpio_pins[] = { 108, 109 };
> +static const unsigned smart_card0_fcb_pins[] = { 45 };
> +static const unsigned smart_card1_fcb_pins[] = { 51 };
> +static const unsigned gpio0_3p3_pins[] = { 176 };
> +static const unsigned gpio1_3p3_pins[] = { 177 };
> +static const unsigned gpio2_3p3_pins[] = { 178 };

Looks good...

> +/*
> + * List of groups names. Need to match the order in cygnus_pin_groups
> + */
> +static const char * const cygnus_pin_group_names[] = {
> +       "gpio0",
> +       "gpio1",
> +       "gpio2",
> +       "gpio3",
> +       "gpio4",
> +       "gpio5",
> +       "gpio6",
> +       "gpio7",
> +       "gpio8",
> +       "gpio9",
> +       "gpio10",
> +       "gpio11",
> +       "gpio12",
> +       "gpio13",
> +       "gpio14",
> +       "gpio15",
> +       "gpio16",
> +       "gpio17",
> +       "gpio18",
> +       "gpio19",
> +       "gpio20",
> +       "gpio21",
> +       "gpio22",
> +       "gpio23",
> +       "pwm0",
> +       "pwm1",
> +       "pwm2",
> +       "pwm3",
> +       "sdio0",
> +       "smart_card0",
> +       "smart_card1",
> +       "spi0",
> +       "spi1",
> +       "spi2",
> +       "spi3",
> +       "d1w",
> +       "lcd",
> +       "uart0",
> +       "uart1_dte",
> +       "uart1",
> +       "uart3",
> +       "qspi",
> +       "nand",
> +       "sdio0_cd",
> +       "sdio0_mmc",
> +       "can0_spi4",
> +       "can1_spi4",
> +       "sdio1_cd",
> +       "sdio1_led",
> +       "sdio1_mmc",
> +       "camera_led",
> +       "camera_rgmii",
> +       "camera_sram_rgmii",
> +       "qspi_gpio",
> +       "smart_card0_fcb",
> +       "smart_card1_fcb",
> +       "gpio0_3p3",
> +       "gpio1_3p3",
> +       "gpio2_3p3",
> +};

This looks very much like function names as noted in the binding.
I would say, suffix every group with _grp or something so it's not
as confusing. Remember, spi0 is a function of the SoC,
pins {1,2} is just a group of pins that it may appear on.

> +#define CYGNUS_PIN_FUNCTION(fcn_name, mux_val)                 \
> +{                                                              \
> +       .name = #fcn_name,                                      \
> +       .group_names = cygnus_pin_group_names,                  \
> +       .num_groups = ARRAY_SIZE(cygnus_pin_group_names),       \
> +       .mux = mux_val,                                         \
> +}
> +
> +/*
> + * Cygnus has 4 alternate functions. All groups can be configured to any of
> + * the 4 alternate functions
> + */
> +static const struct cygnus_pin_function cygnus_pin_functions[] = {
> +       CYGNUS_PIN_FUNCTION(alt1, 0),
> +       CYGNUS_PIN_FUNCTION(alt2, 1),
> +       CYGNUS_PIN_FUNCTION(alt3, 2),
> +       CYGNUS_PIN_FUNCTION(alt4, 3),
> +};

These are not functions. These are per-pin mux ways.

Re-read the documentation of what a function is: it is not something
abstract like "alternative something" but something very direct like
uart0 or spi0.

> +static int cygnus_dt_node_to_map(struct pinctrl_dev *pctrl_dev,
> +               struct device_node *np, struct pinctrl_map **map,
> +               unsigned *num_maps)
> +{

After Sören Brinkmanns patches youy should be able to use core
functions for this and avoid this code altogether.

> +       num_groups = of_property_count_strings(np, "brcm,groups");

As mentioned, just "groups".

> +       ret = of_property_read_string(np, "brcm,function", &function_name);

As mentioned, just "function".

> +       ret = pinctrl_utils_reserve_map(pctrl_dev, map, &reserved_maps,
> +                       num_maps, num_groups);

Good use of utilities!

Apart from this things look nice.

The main comment to address is the definition of functions.

Yours,
Linus Walleij
Ray Jui Jan. 9, 2015, 6:38 p.m. UTC | #2
On 1/9/2015 3:03 AM, Linus Walleij wrote:
> On Fri, Nov 28, 2014 at 12:46 AM, Ray Jui <rjui@broadcom.com> wrote:
> 
>> This adds the initial driver support for the Broadcom Cygnus pinctrl
>> controller. The Cygnus pinctrl controller supports group based
>> alternate function configuration
>>
>> Signed-off-by: Ray Jui <rjui@broadcom.com>
>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
>> ---
>>  drivers/pinctrl/Kconfig              |    7 +
>>  drivers/pinctrl/Makefile             |    1 +
>>  drivers/pinctrl/pinctrl-bcm-cygnus.c |  753 ++++++++++++++++++++++++++++++++++
> 
> With the proliferation of Broadcom drivers, please first send a
> patch moving pinctrl-bcm281xx.c and pinctrl-bcm2835.c to
> drivers/pinctrl/broadcom or something, so we can collect them
> there.
> 
Okay. This change will be included as the first patch in the next patch set.

> I don't know if the hardware has any similarity though, so invite
> the authors of the previous drivers to review this code.
> 
They are completely different. The only similarity between Cygnus and
bcm281xx pinctrl is that they use the same concept of alternation
functions (1, 2, 3, 4) for mux configuration.

>> +config PINCTRL_BCM_CYGNUS
>> +       bool "Broadcom Cygnus pinctrl driver"
>> +       depends on (ARCH_BCM_CYGNUS || COMPILE_TEST)
>> +       select PINMUX
>> +       select PINCONF
>> +       select GENERIC_PINCONF
> 
> Nice that you use GENERIC_PINCONF! :)
> 
>> +/*
>> + * Cygnus pinctrl core
>> + *
>> + * @pctl: pointer to pinctrl_dev
>> + * @dev: pointer to the device
>> + * @base: I/O register base for Cygnus pinctrl configuration
>> + *
>> + */
>> +struct cygnus_pinctrl {
>> +       struct pinctrl_dev *pctl;
>> +       struct device *dev;
>> +       void __iomem *base;
>> +
>> +       const struct pinctrl_pin_desc *pins;
>> +       unsigned num_pins;
> 
> Why is this not simply just a part of struct pinctrl_desc?
> Why does it have to be multiplied here?
> 
Okay. Let me look into this.

>> +/*
>> + * List of groups of pins
>> + */
>> +static const unsigned gpio0_pins[] = { 12 };
>> +static const unsigned gpio1_pins[] = { 13 };
>> +static const unsigned gpio2_pins[] = { 14 };
>> +static const unsigned gpio3_pins[] = { 15 };
>> +static const unsigned gpio4_pins[] = { 16 };
>> +static const unsigned gpio5_pins[] = { 17 };
>> +static const unsigned gpio6_pins[] = { 18 };
>> +static const unsigned gpio7_pins[] = { 19 };
>> +static const unsigned gpio8_pins[] = { 20 };
>> +static const unsigned gpio9_pins[] = { 21 };
>> +static const unsigned gpio10_pins[] = { 22 };
>> +static const unsigned gpio11_pins[] = { 23 };
>> +static const unsigned gpio12_pins[] = { 24 };
>> +static const unsigned gpio13_pins[] = { 25 };
>> +static const unsigned gpio14_pins[] = { 26 };
>> +static const unsigned gpio15_pins[] = { 27 };
>> +static const unsigned gpio16_pins[] = { 28 };
>> +static const unsigned gpio17_pins[] = { 29 };
>> +static const unsigned gpio18_pins[] = { 30 };
>> +static const unsigned gpio19_pins[] = { 31 };
>> +static const unsigned gpio20_pins[] = { 32 };
>> +static const unsigned gpio21_pins[] = { 33 };
>> +static const unsigned gpio22_pins[] = { 34 };
>> +static const unsigned gpio23_pins[] = { 35 };
> 
> Have you considered implementing .gpio_request_enable()
> and .gpio_disable_free() to get around having to have one
> group for each GPIO line?
> 
Okay the Cygnus pin controller is really a mess. GPIO 0 ~ GPIO23 are
really 23 distinct groups, each with one pin. Then the rest of GPIOs go
under other groups. In general, when we set a group to alternate
function 4, all pins become GPIO.

>> +static const unsigned pwm0_pins[] = { 38 };
>> +static const unsigned pwm1_pins[] = { 39 };
>> +static const unsigned pwm2_pins[] = { 40 };
>> +static const unsigned pwm3_pins[] = { 41 };
>> +static const unsigned sdio0_pins[] = { 94, 95, 96, 97, 98, 99 };
>> +static const unsigned smart_card0_pins[] = { 42, 43, 44, 46, 47 };
>> +static const unsigned smart_card1_pins[] = { 48, 49, 50, 52, 53 };
>> +static const unsigned spi0_pins[] = { 54, 55, 56, 57 };
>> +static const unsigned spi1_pins[] = { 58, 59, 60, 61 };
>> +static const unsigned spi2_pins[] = { 62, 63, 64, 65 };
>> +static const unsigned spi3_pins[] = { 66, 67, 68, 69 };
>> +static const unsigned d1w_pins[] = { 10, 11 };
>> +static const unsigned lcd_pins[] = { 126, 127, 128, 129, 130, 131, 132,        133,
>> +       134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
>> +       148, 149, 150, 151, 152, 153, 154, 155 };
>> +static const unsigned uart0_pins[] = { 70, 71, 72, 73 };
>> +static const unsigned uart1_dte_pins[] = { 75, 76, 77, 78 };
>> +static const unsigned uart1_pins[] = { 74, 79, 80, 81 };
>> +static const unsigned uart3_pins[] = { 82, 83 };
>> +static const unsigned qspi_pins[] = { 104, 105, 106, 107 };
>> +static const unsigned nand_pins[] = { 110, 111, 112, 113, 114, 115, 116, 117,
>> +       118, 119, 120, 121, 122, 123, 124, 125 };
>> +static const unsigned sdio0_cd_pins[] = { 103 };
>> +static const unsigned sdio0_mmc_pins[] = { 100, 101, 102 };
>> +static const unsigned can0_spi4_pins[] = { 86, 87 };
>> +static const unsigned can1_spi4_pins[] = { 88, 89 };
>> +static const unsigned sdio1_cd_pins[] = { 93 };
>> +static const unsigned sdio1_led_pins[] = { 84, 85 };
>> +static const unsigned sdio1_mmc_pins[] = { 90, 91, 92 };
>> +static const unsigned camera_led_pins[] = { 156, 157, 158, 159, 160 };
>> +static const unsigned camera_rgmii_pins[] = { 169, 170, 171, 169, 170, 171,
>> +       172, 173 };
>> +static const unsigned camera_sram_rgmii_pins[] = { 161, 162, 163, 164, 165,
>> +       166, 167, 168 };
>> +static const unsigned qspi_gpio_pins[] = { 108, 109 };
>> +static const unsigned smart_card0_fcb_pins[] = { 45 };
>> +static const unsigned smart_card1_fcb_pins[] = { 51 };
>> +static const unsigned gpio0_3p3_pins[] = { 176 };
>> +static const unsigned gpio1_3p3_pins[] = { 177 };
>> +static const unsigned gpio2_3p3_pins[] = { 178 };
> 
> Looks good...
> 
Note these pins are definitions in the driver that help to describe the
pad layout. We can't really configure any individual pins in Cygnus.

>> +/*
>> + * List of groups names. Need to match the order in cygnus_pin_groups
>> + */
>> +static const char * const cygnus_pin_group_names[] = {
>> +       "gpio0",
>> +       "gpio1",
>> +       "gpio2",
>> +       "gpio3",
>> +       "gpio4",
>> +       "gpio5",
>> +       "gpio6",
>> +       "gpio7",
>> +       "gpio8",
>> +       "gpio9",
>> +       "gpio10",
>> +       "gpio11",
>> +       "gpio12",
>> +       "gpio13",
>> +       "gpio14",
>> +       "gpio15",
>> +       "gpio16",
>> +       "gpio17",
>> +       "gpio18",
>> +       "gpio19",
>> +       "gpio20",
>> +       "gpio21",
>> +       "gpio22",
>> +       "gpio23",
>> +       "pwm0",
>> +       "pwm1",
>> +       "pwm2",
>> +       "pwm3",
>> +       "sdio0",
>> +       "smart_card0",
>> +       "smart_card1",
>> +       "spi0",
>> +       "spi1",
>> +       "spi2",
>> +       "spi3",
>> +       "d1w",
>> +       "lcd",
>> +       "uart0",
>> +       "uart1_dte",
>> +       "uart1",
>> +       "uart3",
>> +       "qspi",
>> +       "nand",
>> +       "sdio0_cd",
>> +       "sdio0_mmc",
>> +       "can0_spi4",
>> +       "can1_spi4",
>> +       "sdio1_cd",
>> +       "sdio1_led",
>> +       "sdio1_mmc",
>> +       "camera_led",
>> +       "camera_rgmii",
>> +       "camera_sram_rgmii",
>> +       "qspi_gpio",
>> +       "smart_card0_fcb",
>> +       "smart_card1_fcb",
>> +       "gpio0_3p3",
>> +       "gpio1_3p3",
>> +       "gpio2_3p3",
>> +};
> 
> This looks very much like function names as noted in the binding.
> I would say, suffix every group with _grp or something so it's not
> as confusing. Remember, spi0 is a function of the SoC,
> pins {1,2} is just a group of pins that it may appear on.
> 
Yes, suffix every group with _grp helps a lot to clarify the confusion.
Will fix this.

>> +#define CYGNUS_PIN_FUNCTION(fcn_name, mux_val)                 \
>> +{                                                              \
>> +       .name = #fcn_name,                                      \
>> +       .group_names = cygnus_pin_group_names,                  \
>> +       .num_groups = ARRAY_SIZE(cygnus_pin_group_names),       \
>> +       .mux = mux_val,                                         \
>> +}
>> +
>> +/*
>> + * Cygnus has 4 alternate functions. All groups can be configured to any of
>> + * the 4 alternate functions
>> + */
>> +static const struct cygnus_pin_function cygnus_pin_functions[] = {
>> +       CYGNUS_PIN_FUNCTION(alt1, 0),
>> +       CYGNUS_PIN_FUNCTION(alt2, 1),
>> +       CYGNUS_PIN_FUNCTION(alt3, 2),
>> +       CYGNUS_PIN_FUNCTION(alt4, 3),
>> +};
> 
> These are not functions. These are per-pin mux ways.
> 
> Re-read the documentation of what a function is: it is not something
> abstract like "alternative something" but something very direct like
> uart0 or spi0.
> 
Yes, agree. Will fix.

>> +static int cygnus_dt_node_to_map(struct pinctrl_dev *pctrl_dev,
>> +               struct device_node *np, struct pinctrl_map **map,
>> +               unsigned *num_maps)
>> +{
> 
> After Sören Brinkmanns patches youy should be able to use core
> functions for this and avoid this code altogether.
> 

Will that help to take care our case, based on the way we will use
"function" and "group"?

>> +       num_groups = of_property_count_strings(np, "brcm,groups");
> 
> As mentioned, just "groups".
> 
I guess I will use "group"?

>> +       ret = of_property_read_string(np, "brcm,function", &function_name);
> 
> As mentioned, just "function".
> 
Yes.

>> +       ret = pinctrl_utils_reserve_map(pctrl_dev, map, &reserved_maps,
>> +                       num_maps, num_groups);
> 
> Good use of utilities!
> 
> Apart from this things look nice.
> 
> The main comment to address is the definition of functions.
> 
> Yours,
> Linus Walleij
> 
Thanks a lot for the review!!!
Linus Walleij Jan. 13, 2015, 8:25 a.m. UTC | #3
On Fri, Jan 9, 2015 at 7:38 PM, Ray Jui <rjui@broadcom.com> wrote:
> On 1/9/2015 3:03 AM, Linus Walleij wrote:
>> On Fri, Nov 28, 2014 at 12:46 AM, Ray Jui <rjui@broadcom.com> wrote:

>> I don't know if the hardware has any similarity though, so invite
>> the authors of the previous drivers to review this code.
>>
> They are completely different. The only similarity between Cygnus and
> bcm281xx pinctrl is that they use the same concept of alternation
> functions (1, 2, 3, 4) for mux configuration.

Then you can probably look at that driver for inspiration on how to handle
the situation you described earlier with collissions.

>>> +/*
>>> + * List of groups of pins
>>> + */
>>> +static const unsigned gpio0_pins[] = { 12 };
>>> +static const unsigned gpio1_pins[] = { 13 };
>>> +static const unsigned gpio2_pins[] = { 14 };
>>> +static const unsigned gpio3_pins[] = { 15 };
>>> +static const unsigned gpio4_pins[] = { 16 };
>>> +static const unsigned gpio5_pins[] = { 17 };
>>> +static const unsigned gpio6_pins[] = { 18 };
>>> +static const unsigned gpio7_pins[] = { 19 };
>>> +static const unsigned gpio8_pins[] = { 20 };
>>> +static const unsigned gpio9_pins[] = { 21 };
>>> +static const unsigned gpio10_pins[] = { 22 };
>>> +static const unsigned gpio11_pins[] = { 23 };
>>> +static const unsigned gpio12_pins[] = { 24 };
>>> +static const unsigned gpio13_pins[] = { 25 };
>>> +static const unsigned gpio14_pins[] = { 26 };
>>> +static const unsigned gpio15_pins[] = { 27 };
>>> +static const unsigned gpio16_pins[] = { 28 };
>>> +static const unsigned gpio17_pins[] = { 29 };
>>> +static const unsigned gpio18_pins[] = { 30 };
>>> +static const unsigned gpio19_pins[] = { 31 };
>>> +static const unsigned gpio20_pins[] = { 32 };
>>> +static const unsigned gpio21_pins[] = { 33 };
>>> +static const unsigned gpio22_pins[] = { 34 };
>>> +static const unsigned gpio23_pins[] = { 35 };
>>
>> Have you considered implementing .gpio_request_enable()
>> and .gpio_disable_free() to get around having to have one
>> group for each GPIO line?
>>
> Okay the Cygnus pin controller is really a mess. GPIO 0 ~ GPIO23 are
> really 23 distinct groups, each with one pin. Then the rest of GPIOs go
> under other groups. In general, when we set a group to alternate
> function 4, all pins become GPIO.

It will require some complicated code no matter how you
handle it I'm afraid. Rely on the pin control subsystem
to handle collisions though.

>>> +static const unsigned qspi_gpio_pins[] = { 108, 109 };
>>> +static const unsigned smart_card0_fcb_pins[] = { 45 };
>>> +static const unsigned smart_card1_fcb_pins[] = { 51 };
>>> +static const unsigned gpio0_3p3_pins[] = { 176 };
>>> +static const unsigned gpio1_3p3_pins[] = { 177 };
>>> +static const unsigned gpio2_3p3_pins[] = { 178 };
>>
>> Looks good...
>>
> Note these pins are definitions in the driver that help to describe the
> pad layout. We can't really configure any individual pins in Cygnus.

Yeah it's a groupwise controller then, that's similar to
e.g. the coh901 driver.

We should be able to accomodate this...

>>> +static int cygnus_dt_node_to_map(struct pinctrl_dev *pctrl_dev,
>>> +               struct device_node *np, struct pinctrl_map **map,
>>> +               unsigned *num_maps)
>>> +{
>>
>> After Sören Brinkmanns patches youy should be able to use core
>> functions for this and avoid this code altogether.
>
> Will that help to take care our case, based on the way we will use
> "function" and "group"?

groupS but yes it will work with your controller, though I think
.set_mux and the controller state will need some elaborate code
to handle what the framework requests.

>>> +       num_groups = of_property_count_strings(np, "brcm,groups");
>>
>> As mentioned, just "groups".
>>
> I guess I will use "group"?

No groups, as with the standard attribute "gpios", this may be
a single group too, it's just a standard binding.

Yours,
Linus Walleij
Ray Jui Jan. 13, 2015, 5:17 p.m. UTC | #4
On 1/13/2015 12:25 AM, Linus Walleij wrote:
> On Fri, Jan 9, 2015 at 7:38 PM, Ray Jui <rjui@broadcom.com> wrote:
>> On 1/9/2015 3:03 AM, Linus Walleij wrote:
>>> On Fri, Nov 28, 2014 at 12:46 AM, Ray Jui <rjui@broadcom.com> wrote:
> 
>>> I don't know if the hardware has any similarity though, so invite
>>> the authors of the previous drivers to review this code.
>>>
>> They are completely different. The only similarity between Cygnus and
>> bcm281xx pinctrl is that they use the same concept of alternation
>> functions (1, 2, 3, 4) for mux configuration.
> 
> Then you can probably look at that driver for inspiration on how to handle
> the situation you described earlier with collissions.
> 
>>>> +/*
>>>> + * List of groups of pins
>>>> + */
>>>> +static const unsigned gpio0_pins[] = { 12 };
>>>> +static const unsigned gpio1_pins[] = { 13 };
>>>> +static const unsigned gpio2_pins[] = { 14 };
>>>> +static const unsigned gpio3_pins[] = { 15 };
>>>> +static const unsigned gpio4_pins[] = { 16 };
>>>> +static const unsigned gpio5_pins[] = { 17 };
>>>> +static const unsigned gpio6_pins[] = { 18 };
>>>> +static const unsigned gpio7_pins[] = { 19 };
>>>> +static const unsigned gpio8_pins[] = { 20 };
>>>> +static const unsigned gpio9_pins[] = { 21 };
>>>> +static const unsigned gpio10_pins[] = { 22 };
>>>> +static const unsigned gpio11_pins[] = { 23 };
>>>> +static const unsigned gpio12_pins[] = { 24 };
>>>> +static const unsigned gpio13_pins[] = { 25 };
>>>> +static const unsigned gpio14_pins[] = { 26 };
>>>> +static const unsigned gpio15_pins[] = { 27 };
>>>> +static const unsigned gpio16_pins[] = { 28 };
>>>> +static const unsigned gpio17_pins[] = { 29 };
>>>> +static const unsigned gpio18_pins[] = { 30 };
>>>> +static const unsigned gpio19_pins[] = { 31 };
>>>> +static const unsigned gpio20_pins[] = { 32 };
>>>> +static const unsigned gpio21_pins[] = { 33 };
>>>> +static const unsigned gpio22_pins[] = { 34 };
>>>> +static const unsigned gpio23_pins[] = { 35 };
>>>
>>> Have you considered implementing .gpio_request_enable()
>>> and .gpio_disable_free() to get around having to have one
>>> group for each GPIO line?
>>>
>> Okay the Cygnus pin controller is really a mess. GPIO 0 ~ GPIO23 are
>> really 23 distinct groups, each with one pin. Then the rest of GPIOs go
>> under other groups. In general, when we set a group to alternate
>> function 4, all pins become GPIO.
> 
> It will require some complicated code no matter how you
> handle it I'm afraid. Rely on the pin control subsystem
> to handle collisions though.
> 
>>>> +static const unsigned qspi_gpio_pins[] = { 108, 109 };
>>>> +static const unsigned smart_card0_fcb_pins[] = { 45 };
>>>> +static const unsigned smart_card1_fcb_pins[] = { 51 };
>>>> +static const unsigned gpio0_3p3_pins[] = { 176 };
>>>> +static const unsigned gpio1_3p3_pins[] = { 177 };
>>>> +static const unsigned gpio2_3p3_pins[] = { 178 };
>>>
>>> Looks good...
>>>
>> Note these pins are definitions in the driver that help to describe the
>> pad layout. We can't really configure any individual pins in Cygnus.
> 
> Yeah it's a groupwise controller then, that's similar to
> e.g. the coh901 driver.
> 
> We should be able to accomodate this...
> 
Okay will check the coh901 driver.

>>>> +static int cygnus_dt_node_to_map(struct pinctrl_dev *pctrl_dev,
>>>> +               struct device_node *np, struct pinctrl_map **map,
>>>> +               unsigned *num_maps)
>>>> +{
>>>
>>> After Sören Brinkmanns patches youy should be able to use core
>>> functions for this and avoid this code altogether.
>>
>> Will that help to take care our case, based on the way we will use
>> "function" and "group"?
> 
> groupS but yes it will work with your controller, though I think
> .set_mux and the controller state will need some elaborate code
> to handle what the framework requests.
> 
Thanks.

>>>> +       num_groups = of_property_count_strings(np, "brcm,groups");
>>>
>>> As mentioned, just "groups".
>>>
>> I guess I will use "group"?
> 
> No groups, as with the standard attribute "gpios", this may be
> a single group too, it's just a standard binding.
> 
Okay.

> Yours,
> Linus Walleij
>
diff mbox

Patch

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d014f22..4549e9f 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -85,6 +85,13 @@  config PINCTRL_BCM281XX
 	  BCM28145, and BCM28155 SoCs.  This driver requires the pinctrl
 	  framework.  GPIO is provided by a separate GPIO driver.
 
+config PINCTRL_BCM_CYGNUS
+	bool "Broadcom Cygnus pinctrl driver"
+	depends on (ARCH_BCM_CYGNUS || COMPILE_TEST)
+	select PINMUX
+	select PINCONF
+	select GENERIC_PINCONF
+
 config PINCTRL_LANTIQ
 	bool
 	depends on LANTIQ
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c030b3d..4ed8e8a 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -16,6 +16,7 @@  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_BCM_CYGNUS)	+= pinctrl-bcm-cygnus.o
 obj-$(CONFIG_PINCTRL_FALCON)	+= pinctrl-falcon.o
 obj-$(CONFIG_PINCTRL_PALMAS)	+= pinctrl-palmas.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP)	+= pinctrl-rockchip.o
diff --git a/drivers/pinctrl/pinctrl-bcm-cygnus.c b/drivers/pinctrl/pinctrl-bcm-cygnus.c
new file mode 100644
index 0000000..eb6e27a
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-bcm-cygnus.c
@@ -0,0 +1,753 @@ 
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.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 <linux/slab.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+
+/*
+ * Alternate function configuration
+ *
+ * @name: name of the alternate function
+ * @group_names: array of strings of group names that can be supported by this
+ * alternate function
+ * @num_groups: total number of groups that can be supported by this alternate
+ * function
+ * @mux: mux setting for this alternate function to be programed
+ */
+struct cygnus_pin_function {
+	const char *name;
+	const char * const *group_names;
+	const unsigned num_groups;
+	unsigned int mux;
+};
+
+/*
+ * Cygnus allows group based pinmux configuration
+ *
+ * @name: name of the group
+ * @pins: array of pins used by this group
+ * @num_pins: total number of pins used by this group
+ * @offset: register offset for pinmux configuration of this group
+ * @shift: bit shift for pinmux configuration of this group
+ */
+struct cygnus_pin_group {
+	const char *name;
+	const unsigned *pins;
+	const unsigned num_pins;
+	const unsigned int offset;
+	const unsigned int shift;
+};
+
+/*
+ * Cygnus pinctrl core
+ *
+ * @pctl: pointer to pinctrl_dev
+ * @dev: pointer to the device
+ * @base: I/O register base for Cygnus pinctrl configuration
+ *
+ */
+struct cygnus_pinctrl {
+	struct pinctrl_dev *pctl;
+	struct device *dev;
+	void __iomem *base;
+
+	const struct pinctrl_pin_desc *pins;
+	unsigned num_pins;
+
+	const struct cygnus_pin_group *groups;
+	unsigned num_groups;
+
+	const struct cygnus_pin_function *functions;
+	unsigned num_functions;
+};
+
+#define CYGNUS_PIN_GROUP(group_name, off, sh)		\
+{							\
+	.name = #group_name,				\
+	.pins = group_name##_pins,			\
+	.num_pins = ARRAY_SIZE(group_name##_pins),	\
+	.offset = off,					\
+	.shift = sh,					\
+}
+
+/*
+ * The following pin description is based on Cygnus I/O MUX spreadsheet
+ */
+static const struct pinctrl_pin_desc cygnus_pinctrl_pins[] = {
+	PINCTRL_PIN(0, "ext_device_reset_n"),
+	PINCTRL_PIN(1, "chip_mode0"),
+	PINCTRL_PIN(2, "chip_mode1"),
+	PINCTRL_PIN(3, "chip_mode2"),
+	PINCTRL_PIN(4, "chip_mode3"),
+	PINCTRL_PIN(5, "chip_mode4"),
+	PINCTRL_PIN(6, "bsc0_scl"),
+	PINCTRL_PIN(7, "bsc0_sda"),
+	PINCTRL_PIN(8, "bsc1_scl"),
+	PINCTRL_PIN(9, "bsc1_sda"),
+	PINCTRL_PIN(10, "d1w_dq"),
+	PINCTRL_PIN(11, "d1wowstz_l"),
+	PINCTRL_PIN(12, "gpio0"),
+	PINCTRL_PIN(13, "gpio1"),
+	PINCTRL_PIN(14, "gpio2"),
+	PINCTRL_PIN(15, "gpio3"),
+	PINCTRL_PIN(16, "gpio4"),
+	PINCTRL_PIN(17, "gpio5"),
+	PINCTRL_PIN(18, "gpio6"),
+	PINCTRL_PIN(19, "gpio7"),
+	PINCTRL_PIN(20, "gpio8"),
+	PINCTRL_PIN(21, "gpio9"),
+	PINCTRL_PIN(22, "gpio10"),
+	PINCTRL_PIN(23, "gpio11"),
+	PINCTRL_PIN(24, "gpio12"),
+	PINCTRL_PIN(25, "gpio13"),
+	PINCTRL_PIN(26, "gpio14"),
+	PINCTRL_PIN(27, "gpio15"),
+	PINCTRL_PIN(28, "gpio16"),
+	PINCTRL_PIN(29, "gpio17"),
+	PINCTRL_PIN(30, "gpio18"),
+	PINCTRL_PIN(31, "gpio19"),
+	PINCTRL_PIN(32, "gpio20"),
+	PINCTRL_PIN(33, "gpio21"),
+	PINCTRL_PIN(34, "gpio22"),
+	PINCTRL_PIN(35, "gpio23"),
+	PINCTRL_PIN(36, "mdc"),
+	PINCTRL_PIN(37, "mdio"),
+	PINCTRL_PIN(38, "pwm0"),
+	PINCTRL_PIN(39, "pwm1"),
+	PINCTRL_PIN(40, "pwm2"),
+	PINCTRL_PIN(41, "pwm3"),
+	PINCTRL_PIN(42, "sc0_clk"),
+	PINCTRL_PIN(43, "sc0_cmdvcc_l"),
+	PINCTRL_PIN(44, "sc0_detect"),
+	PINCTRL_PIN(45, "sc0_fcb"),
+	PINCTRL_PIN(46, "sc0_io"),
+	PINCTRL_PIN(47, "sc0_rst_l"),
+	PINCTRL_PIN(48, "sc1_clk"),
+	PINCTRL_PIN(49, "sc1_cmdvcc_l"),
+	PINCTRL_PIN(50, "sc1_detect"),
+	PINCTRL_PIN(51, "sc1_fcb"),
+	PINCTRL_PIN(52, "sc1_io"),
+	PINCTRL_PIN(53, "sc1_rst_l"),
+	PINCTRL_PIN(54, "spi0_clk"),
+	PINCTRL_PIN(55, "spi0_mosi"),
+	PINCTRL_PIN(56, "spi0_miso"),
+	PINCTRL_PIN(57, "spi0_ss"),
+	PINCTRL_PIN(58, "spi1_clk"),
+	PINCTRL_PIN(59, "spi1_mosi"),
+	PINCTRL_PIN(60, "spi1_miso"),
+	PINCTRL_PIN(61, "spi1_ss"),
+	PINCTRL_PIN(62, "spi2_clk"),
+	PINCTRL_PIN(63, "spi2_mosi"),
+	PINCTRL_PIN(64, "spi2_miso"),
+	PINCTRL_PIN(65, "spi2_ss"),
+	PINCTRL_PIN(66, "spi3_clk"),
+	PINCTRL_PIN(67, "spi3_mosi"),
+	PINCTRL_PIN(68, "spi3_miso"),
+	PINCTRL_PIN(69, "spi3_ss"),
+	PINCTRL_PIN(70, "uart0_cts"),
+	PINCTRL_PIN(71, "uart0_rts"),
+	PINCTRL_PIN(72, "uart0_rx"),
+	PINCTRL_PIN(73, "uart0_tx"),
+	PINCTRL_PIN(74, "uart1_cts"),
+	PINCTRL_PIN(75, "uart1_dcd"),
+	PINCTRL_PIN(76, "uart1_dsr"),
+	PINCTRL_PIN(77, "uart1_dtr"),
+	PINCTRL_PIN(78, "uart1_ri"),
+	PINCTRL_PIN(79, "uart1_rts"),
+	PINCTRL_PIN(80, "uart1_rx"),
+	PINCTRL_PIN(81, "uart1_tx"),
+	PINCTRL_PIN(82, "uart3_rx"),
+	PINCTRL_PIN(83, "uart3_tx"),
+	PINCTRL_PIN(84, "sdio1_clk_sdcard"),
+	PINCTRL_PIN(85, "sdio1_cmd"),
+	PINCTRL_PIN(86, "sdio1_data0"),
+	PINCTRL_PIN(87, "sdio1_data1"),
+	PINCTRL_PIN(88, "sdio1_data2"),
+	PINCTRL_PIN(89, "sdio1_data3"),
+	PINCTRL_PIN(90, "sdio1_wp_n"),
+	PINCTRL_PIN(91, "sdio1_card_rst"),
+	PINCTRL_PIN(92, "sdio1_led_on"),
+	PINCTRL_PIN(93, "sdio1_cd"),
+	PINCTRL_PIN(94, "sdio0_clk_sdcard"),
+	PINCTRL_PIN(95, "sdio0_cmd"),
+	PINCTRL_PIN(96, "sdio0_data0"),
+	PINCTRL_PIN(97, "sdio0_data1"),
+	PINCTRL_PIN(98, "sdio0_data2"),
+	PINCTRL_PIN(99, "sdio0_data3"),
+	PINCTRL_PIN(100, "sdio0_wp_n"),
+	PINCTRL_PIN(101, "sdio0_card_rst"),
+	PINCTRL_PIN(102, "sdio0_led_on"),
+	PINCTRL_PIN(103, "sdio0_cd"),
+	PINCTRL_PIN(104, "sflash_clk"),
+	PINCTRL_PIN(105, "sflash_cs_l"),
+	PINCTRL_PIN(106, "sflash_mosi"),
+	PINCTRL_PIN(107, "sflash_miso"),
+	PINCTRL_PIN(108, "sflash_wp_n"),
+	PINCTRL_PIN(109, "sflash_hold_n"),
+	PINCTRL_PIN(110, "nand_ale"),
+	PINCTRL_PIN(111, "nand_ce0_l"),
+	PINCTRL_PIN(112, "nand_ce1_l"),
+	PINCTRL_PIN(113, "nand_cle"),
+	PINCTRL_PIN(114, "nand_dq0"),
+	PINCTRL_PIN(115, "nand_dq1"),
+	PINCTRL_PIN(116, "nand_dq2"),
+	PINCTRL_PIN(117, "nand_dq3"),
+	PINCTRL_PIN(118, "nand_dq4"),
+	PINCTRL_PIN(119, "nand_dq5"),
+	PINCTRL_PIN(120, "nand_dq6"),
+	PINCTRL_PIN(121, "nand_dq7"),
+	PINCTRL_PIN(122, "nand_rb_l"),
+	PINCTRL_PIN(123, "nand_re_l"),
+	PINCTRL_PIN(124, "nand_we_l"),
+	PINCTRL_PIN(125, "nand_wp_l"),
+	PINCTRL_PIN(126, "lcd_clac"),
+	PINCTRL_PIN(127, "lcd_clcp"),
+	PINCTRL_PIN(128, "lcd_cld0"),
+	PINCTRL_PIN(129, "lcd_cld1"),
+	PINCTRL_PIN(130, "lcd_cld10"),
+	PINCTRL_PIN(131, "lcd_cld11"),
+	PINCTRL_PIN(132, "lcd_cld12"),
+	PINCTRL_PIN(133, "lcd_cld13"),
+	PINCTRL_PIN(134, "lcd_cld14"),
+	PINCTRL_PIN(135, "lcd_cld15"),
+	PINCTRL_PIN(136, "lcd_cld16"),
+	PINCTRL_PIN(137, "lcd_cld17"),
+	PINCTRL_PIN(138, "lcd_cld18"),
+	PINCTRL_PIN(139, "lcd_cld19"),
+	PINCTRL_PIN(140, "lcd_cld2"),
+	PINCTRL_PIN(141, "lcd_cld20"),
+	PINCTRL_PIN(142, "lcd_cld21"),
+	PINCTRL_PIN(143, "lcd_cld22"),
+	PINCTRL_PIN(144, "lcd_cld23"),
+	PINCTRL_PIN(145, "lcd_cld3"),
+	PINCTRL_PIN(146, "lcd_cld4"),
+	PINCTRL_PIN(147, "lcd_cld5"),
+	PINCTRL_PIN(148, "lcd_cld6"),
+	PINCTRL_PIN(149, "lcd_cld7"),
+	PINCTRL_PIN(150, "lcd_cld8"),
+	PINCTRL_PIN(151, "lcd_cld9"),
+	PINCTRL_PIN(152, "lcd_clfp"),
+	PINCTRL_PIN(153, "lcd_clle"),
+	PINCTRL_PIN(154, "lcd_cllp"),
+	PINCTRL_PIN(155, "lcd_clpower"),
+	PINCTRL_PIN(156, "camera_vsync"),
+	PINCTRL_PIN(157, "camera_trigger"),
+	PINCTRL_PIN(158, "camera_strobe"),
+	PINCTRL_PIN(159, "camera_standby"),
+	PINCTRL_PIN(160, "camera_reset_n"),
+	PINCTRL_PIN(161, "camera_pixdata9"),
+	PINCTRL_PIN(162, "camera_pixdata8"),
+	PINCTRL_PIN(163, "camera_pixdata7"),
+	PINCTRL_PIN(164, "camera_pixdata6"),
+	PINCTRL_PIN(165, "camera_pixdata5"),
+	PINCTRL_PIN(166, "camera_pixdata4"),
+	PINCTRL_PIN(167, "camera_pixdata3"),
+	PINCTRL_PIN(168, "camera_pixdata2"),
+	PINCTRL_PIN(169, "camera_pixdata1"),
+	PINCTRL_PIN(170, "camera_pixdata0"),
+	PINCTRL_PIN(171, "camera_pixclk"),
+	PINCTRL_PIN(172, "camera_hsync"),
+	PINCTRL_PIN(173, "camera_pll_ref_clk"),
+	PINCTRL_PIN(174, "usb_id_indication"),
+	PINCTRL_PIN(175, "usb_vbus_indication"),
+	PINCTRL_PIN(176, "gpio0_3p3"),
+	PINCTRL_PIN(177, "gpio1_3p3"),
+	PINCTRL_PIN(178, "gpio2_3p3"),
+	PINCTRL_PIN(179, "gpio3_3p3"),
+};
+
+/*
+ * List of groups of pins
+ */
+static const unsigned gpio0_pins[] = { 12 };
+static const unsigned gpio1_pins[] = { 13 };
+static const unsigned gpio2_pins[] = { 14 };
+static const unsigned gpio3_pins[] = { 15 };
+static const unsigned gpio4_pins[] = { 16 };
+static const unsigned gpio5_pins[] = { 17 };
+static const unsigned gpio6_pins[] = { 18 };
+static const unsigned gpio7_pins[] = { 19 };
+static const unsigned gpio8_pins[] = { 20 };
+static const unsigned gpio9_pins[] = { 21 };
+static const unsigned gpio10_pins[] = { 22 };
+static const unsigned gpio11_pins[] = { 23 };
+static const unsigned gpio12_pins[] = { 24 };
+static const unsigned gpio13_pins[] = { 25 };
+static const unsigned gpio14_pins[] = { 26 };
+static const unsigned gpio15_pins[] = { 27 };
+static const unsigned gpio16_pins[] = { 28 };
+static const unsigned gpio17_pins[] = { 29 };
+static const unsigned gpio18_pins[] = { 30 };
+static const unsigned gpio19_pins[] = { 31 };
+static const unsigned gpio20_pins[] = { 32 };
+static const unsigned gpio21_pins[] = { 33 };
+static const unsigned gpio22_pins[] = { 34 };
+static const unsigned gpio23_pins[] = { 35 };
+static const unsigned pwm0_pins[] = { 38 };
+static const unsigned pwm1_pins[] = { 39 };
+static const unsigned pwm2_pins[] = { 40 };
+static const unsigned pwm3_pins[] = { 41 };
+static const unsigned sdio0_pins[] = { 94, 95, 96, 97, 98, 99 };
+static const unsigned smart_card0_pins[] = { 42, 43, 44, 46, 47 };
+static const unsigned smart_card1_pins[] = { 48, 49, 50, 52, 53 };
+static const unsigned spi0_pins[] = { 54, 55, 56, 57 };
+static const unsigned spi1_pins[] = { 58, 59, 60, 61 };
+static const unsigned spi2_pins[] = { 62, 63, 64, 65 };
+static const unsigned spi3_pins[] = { 66, 67, 68, 69 };
+static const unsigned d1w_pins[] = { 10, 11 };
+static const unsigned lcd_pins[] = { 126, 127, 128, 129, 130, 131, 132,	133,
+	134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
+	148, 149, 150, 151, 152, 153, 154, 155 };
+static const unsigned uart0_pins[] = { 70, 71, 72, 73 };
+static const unsigned uart1_dte_pins[] = { 75, 76, 77, 78 };
+static const unsigned uart1_pins[] = { 74, 79, 80, 81 };
+static const unsigned uart3_pins[] = { 82, 83 };
+static const unsigned qspi_pins[] = { 104, 105, 106, 107 };
+static const unsigned nand_pins[] = { 110, 111, 112, 113, 114, 115, 116, 117,
+	118, 119, 120, 121, 122, 123, 124, 125 };
+static const unsigned sdio0_cd_pins[] = { 103 };
+static const unsigned sdio0_mmc_pins[] = { 100, 101, 102 };
+static const unsigned can0_spi4_pins[] = { 86, 87 };
+static const unsigned can1_spi4_pins[] = { 88, 89 };
+static const unsigned sdio1_cd_pins[] = { 93 };
+static const unsigned sdio1_led_pins[] = { 84, 85 };
+static const unsigned sdio1_mmc_pins[] = { 90, 91, 92 };
+static const unsigned camera_led_pins[] = { 156, 157, 158, 159, 160 };
+static const unsigned camera_rgmii_pins[] = { 169, 170, 171, 169, 170, 171,
+	172, 173 };
+static const unsigned camera_sram_rgmii_pins[] = { 161, 162, 163, 164, 165,
+	166, 167, 168 };
+static const unsigned qspi_gpio_pins[] = { 108, 109 };
+static const unsigned smart_card0_fcb_pins[] = { 45 };
+static const unsigned smart_card1_fcb_pins[] = { 51 };
+static const unsigned gpio0_3p3_pins[] = { 176 };
+static const unsigned gpio1_3p3_pins[] = { 177 };
+static const unsigned gpio2_3p3_pins[] = { 178 };
+
+/*
+ * List of groups names. Need to match the order in cygnus_pin_groups
+ */
+static const char * const cygnus_pin_group_names[] = {
+	"gpio0",
+	"gpio1",
+	"gpio2",
+	"gpio3",
+	"gpio4",
+	"gpio5",
+	"gpio6",
+	"gpio7",
+	"gpio8",
+	"gpio9",
+	"gpio10",
+	"gpio11",
+	"gpio12",
+	"gpio13",
+	"gpio14",
+	"gpio15",
+	"gpio16",
+	"gpio17",
+	"gpio18",
+	"gpio19",
+	"gpio20",
+	"gpio21",
+	"gpio22",
+	"gpio23",
+	"pwm0",
+	"pwm1",
+	"pwm2",
+	"pwm3",
+	"sdio0",
+	"smart_card0",
+	"smart_card1",
+	"spi0",
+	"spi1",
+	"spi2",
+	"spi3",
+	"d1w",
+	"lcd",
+	"uart0",
+	"uart1_dte",
+	"uart1",
+	"uart3",
+	"qspi",
+	"nand",
+	"sdio0_cd",
+	"sdio0_mmc",
+	"can0_spi4",
+	"can1_spi4",
+	"sdio1_cd",
+	"sdio1_led",
+	"sdio1_mmc",
+	"camera_led",
+	"camera_rgmii",
+	"camera_sram_rgmii",
+	"qspi_gpio",
+	"smart_card0_fcb",
+	"smart_card1_fcb",
+	"gpio0_3p3",
+	"gpio1_3p3",
+	"gpio2_3p3",
+};
+
+/*
+ * List of groups. Need to match the order in cygnus_pin_group_names
+ */
+static const struct cygnus_pin_group cygnus_pin_groups[] = {
+	CYGNUS_PIN_GROUP(gpio0, 0x0, 0),
+	CYGNUS_PIN_GROUP(gpio1, 0x0, 4),
+	CYGNUS_PIN_GROUP(gpio2, 0x0, 8),
+	CYGNUS_PIN_GROUP(gpio3, 0x0, 12),
+	CYGNUS_PIN_GROUP(gpio4, 0x0, 16),
+	CYGNUS_PIN_GROUP(gpio5, 0x0, 20),
+	CYGNUS_PIN_GROUP(gpio6, 0x0, 24),
+	CYGNUS_PIN_GROUP(gpio7, 0x0, 28),
+	CYGNUS_PIN_GROUP(gpio8, 0x4, 0),
+	CYGNUS_PIN_GROUP(gpio9, 0x4, 4),
+	CYGNUS_PIN_GROUP(gpio10, 0x4, 8),
+	CYGNUS_PIN_GROUP(gpio11, 0x4, 12),
+	CYGNUS_PIN_GROUP(gpio12, 0x4, 16),
+	CYGNUS_PIN_GROUP(gpio13, 0x4, 20),
+	CYGNUS_PIN_GROUP(gpio14, 0x4, 24),
+	CYGNUS_PIN_GROUP(gpio15, 0x4, 28),
+	CYGNUS_PIN_GROUP(gpio16, 0x8, 0),
+	CYGNUS_PIN_GROUP(gpio17, 0x8, 4),
+	CYGNUS_PIN_GROUP(gpio18, 0x8, 8),
+	CYGNUS_PIN_GROUP(gpio19, 0x8, 12),
+	CYGNUS_PIN_GROUP(gpio20, 0x8, 16),
+	CYGNUS_PIN_GROUP(gpio21, 0x8, 20),
+	CYGNUS_PIN_GROUP(gpio22, 0x8, 24),
+	CYGNUS_PIN_GROUP(gpio23, 0x8, 28),
+	CYGNUS_PIN_GROUP(pwm0, 0xc, 0),
+	CYGNUS_PIN_GROUP(pwm1, 0xc, 4),
+	CYGNUS_PIN_GROUP(pwm2, 0xc, 8),
+	CYGNUS_PIN_GROUP(pwm3, 0xc, 12),
+	CYGNUS_PIN_GROUP(sdio0, 0xc, 16),
+	CYGNUS_PIN_GROUP(smart_card0, 0xc, 20),
+	CYGNUS_PIN_GROUP(smart_card1, 0xc, 24),
+	CYGNUS_PIN_GROUP(spi0, 0x10, 0),
+	CYGNUS_PIN_GROUP(spi1, 0x10, 4),
+	CYGNUS_PIN_GROUP(spi2, 0x10, 8),
+	CYGNUS_PIN_GROUP(spi3, 0x10, 12),
+	CYGNUS_PIN_GROUP(d1w, 0x10, 16),
+	CYGNUS_PIN_GROUP(lcd, 0x10, 20),
+	CYGNUS_PIN_GROUP(uart0, 0x14, 0),
+	CYGNUS_PIN_GROUP(uart1_dte, 0x14, 4),
+	CYGNUS_PIN_GROUP(uart1, 0x14, 8),
+	CYGNUS_PIN_GROUP(uart3, 0x14, 12),
+	CYGNUS_PIN_GROUP(qspi, 0x14, 16),
+	CYGNUS_PIN_GROUP(nand, 0x14, 20),
+	CYGNUS_PIN_GROUP(sdio0_cd, 0x18, 0),
+	CYGNUS_PIN_GROUP(sdio0_mmc, 0x18, 4),
+	CYGNUS_PIN_GROUP(can0_spi4, 0x18, 8),
+	CYGNUS_PIN_GROUP(can1_spi4, 0x18, 12),
+	CYGNUS_PIN_GROUP(sdio1_cd, 0x18, 16),
+	CYGNUS_PIN_GROUP(sdio1_led, 0x18, 20),
+	CYGNUS_PIN_GROUP(sdio1_mmc, 0x18, 24),
+	CYGNUS_PIN_GROUP(camera_led, 0x1c, 0),
+	CYGNUS_PIN_GROUP(camera_rgmii, 0x1c, 4),
+	CYGNUS_PIN_GROUP(camera_sram_rgmii, 0x1c, 8),
+	CYGNUS_PIN_GROUP(qspi_gpio, 0x1c, 12),
+	CYGNUS_PIN_GROUP(smart_card0_fcb, 0x20, 0),
+	CYGNUS_PIN_GROUP(smart_card1_fcb, 0x20, 4),
+	CYGNUS_PIN_GROUP(gpio0_3p3, 0x28, 0),
+	CYGNUS_PIN_GROUP(gpio1_3p3, 0x28, 4),
+	CYGNUS_PIN_GROUP(gpio2_3p3, 0x28, 8),
+};
+
+#define CYGNUS_PIN_FUNCTION(fcn_name, mux_val)			\
+{								\
+	.name = #fcn_name,					\
+	.group_names = cygnus_pin_group_names,			\
+	.num_groups = ARRAY_SIZE(cygnus_pin_group_names),	\
+	.mux = mux_val,						\
+}
+
+/*
+ * Cygnus has 4 alternate functions. All groups can be configured to any of
+ * the 4 alternate functions
+ */
+static const struct cygnus_pin_function cygnus_pin_functions[] = {
+	CYGNUS_PIN_FUNCTION(alt1, 0),
+	CYGNUS_PIN_FUNCTION(alt2, 1),
+	CYGNUS_PIN_FUNCTION(alt3, 2),
+	CYGNUS_PIN_FUNCTION(alt4, 3),
+};
+
+static int cygnus_get_groups_count(struct pinctrl_dev *pctrl_dev)
+{
+	struct cygnus_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+	return pinctrl->num_groups;
+}
+
+static const char *cygnus_get_group_name(struct pinctrl_dev *pctrl_dev,
+		unsigned selector)
+{
+	struct cygnus_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+	return pinctrl->groups[selector].name;
+}
+
+static int cygnus_get_group_pins(struct pinctrl_dev *pctrl_dev,
+		unsigned selector, const unsigned **pins,
+		unsigned *num_pins)
+{
+	struct cygnus_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+	*pins = pinctrl->groups[selector].pins;
+	*num_pins = pinctrl->groups[selector].num_pins;
+
+	return 0;
+}
+
+static void cygnus_pin_dbg_show(struct pinctrl_dev *pctrl_dev,
+		struct seq_file *s, unsigned offset)
+{
+	seq_printf(s, " %s", dev_name(pctrl_dev->dev));
+}
+
+static int find_matched_function(const char *function_name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cygnus_pin_functions); i++) {
+		if (!strcmp(cygnus_pin_functions[i].name, function_name))
+			return (int)cygnus_pin_functions[i].mux;
+	}
+
+	return -EINVAL;
+}
+
+static int cygnus_dt_node_to_map(struct pinctrl_dev *pctrl_dev,
+		struct device_node *np, struct pinctrl_map **map,
+		unsigned *num_maps)
+{
+	int ret, num_groups;
+	unsigned reserved_maps = 0;
+	struct property *prop;
+	const char *group_name, *function_name;
+
+	*map = NULL;
+	*num_maps = 0;
+
+	num_groups = of_property_count_strings(np, "brcm,groups");
+	if (num_groups < 0) {
+		dev_err(pctrl_dev->dev,
+			"could not parse property brcm,groups\n");
+		return -EINVAL;
+	}
+
+	ret = of_property_read_string(np, "brcm,function", &function_name);
+	if (ret < 0) {
+		dev_err(pctrl_dev->dev,
+			"could not parse property brcm,function\n");
+		return -EINVAL;
+	}
+
+	/* make sure it's a valid alternate function */
+	ret = find_matched_function(function_name);
+	if (ret < 0) {
+		dev_err(pctrl_dev->dev, "invalid function name: %s\n",
+				function_name);
+	}
+
+	ret = pinctrl_utils_reserve_map(pctrl_dev, map, &reserved_maps,
+			num_maps, num_groups);
+	if (ret) {
+		dev_err(pctrl_dev->dev, "unable to reserve map\n");
+		return ret;
+	}
+
+	of_property_for_each_string(np, "brcm,groups", prop, group_name) {
+		ret = pinctrl_utils_add_map_mux(pctrl_dev, map,
+				&reserved_maps, num_maps, group_name,
+				function_name);
+		if (ret) {
+			dev_err(pctrl_dev->dev, "can't add map: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static struct pinctrl_ops cygnus_pinctrl_ops = {
+	.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].group_names;
+	*num_groups = pinctrl->functions[selector].num_groups;
+
+	return 0;
+}
+
+static int cygnus_pinmux_set_mux(struct pinctrl_dev *pctrl_dev,
+		unsigned function_selector, unsigned group_selector)
+{
+	struct cygnus_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+	const struct cygnus_pin_function *function =
+			&pinctrl->functions[function_selector];
+	const struct cygnus_pin_group *group =
+			&pinctrl->groups[group_selector];
+	u32 val, mask = 0x7;
+
+	dev_dbg(pctrl_dev->dev,
+	"group:%s with offset:0x%08x shift:%u set to function: %s mux:%u\n",
+		group->name, group->offset, group->shift, function->name,
+		function->mux);
+
+	val = readl(pinctrl->base + group->offset);
+	val &= ~(mask << group->shift);
+	val |= function->mux << group->shift;
+	writel(val, pinctrl->base + group->offset);
+
+	return 0;
+}
+
+static struct pinmux_ops cygnus_pinmux_ops = {
+	.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,
+};
+
+static struct pinctrl_desc cygnus_pinctrl_desc = {
+	.pctlops = &cygnus_pinctrl_ops,
+	.pmxops = &cygnus_pinmux_ops,
+	.owner = THIS_MODULE,
+};
+
+static int cygnus_pinctrl_probe(struct platform_device *pdev)
+{
+	struct cygnus_pinctrl *pinctrl;
+	struct resource *res;
+
+	pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
+	if (!pinctrl) {
+		dev_err(&pdev->dev, "unable to allocate memory\n");
+		return -ENOMEM;
+	}
+	pinctrl->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "unable to get resource\n");
+		return -ENOENT;
+	}
+
+	pinctrl->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pinctrl->base)) {
+		dev_err(&pdev->dev, "unable to map I/O space\n");
+		return PTR_ERR(pinctrl->base);
+	}
+
+	pinctrl->pins = cygnus_pinctrl_pins;
+	pinctrl->num_pins = ARRAY_SIZE(cygnus_pinctrl_pins);
+	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.name = dev_name(&pdev->dev);
+	cygnus_pinctrl_desc.pins = cygnus_pinctrl_pins;
+	cygnus_pinctrl_desc.npins = ARRAY_SIZE(cygnus_pinctrl_pins);
+
+	pinctrl->pctl = pinctrl_register(&cygnus_pinctrl_desc, &pdev->dev,
+			pinctrl);
+	if (!pinctrl->pctl) {
+		dev_err(&pdev->dev, "unable to register cygnus pinctrl\n");
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, pinctrl);
+
+	return 0;
+}
+
+static int cygnus_pinctrl_remove(struct platform_device *pdev)
+{
+	struct cygnus_pinctrl *pinctrl = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(pinctrl->pctl);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct of_device_id cygnus_pinctrl_of_match[] = {
+	{ .compatible = "brcm,cygnus-pinctrl", },
+	{ },
+};
+
+static struct platform_driver cygnus_pinctrl_driver = {
+	.driver = {
+		.name = "cygnus-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = cygnus_pinctrl_of_match,
+	},
+	.probe = cygnus_pinctrl_probe,
+	.remove = cygnus_pinctrl_remove,
+};
+
+static int __init cygnus_pinctrl_init(void)
+{
+	return platform_driver_register(&cygnus_pinctrl_driver);
+}
+arch_initcall(cygnus_pinctrl_init);
+
+static void __exit cygnus_pinctrl_exit(void)
+{
+	platform_driver_unregister(&cygnus_pinctrl_driver);
+}
+module_exit(cygnus_pinctrl_exit);
+
+MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom Cygnus pinctrl driver");
+MODULE_LICENSE("GPL v2");