Message ID | 1417131990-17954-3-git-send-email-rjui@broadcom.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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
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!!!
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
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 --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");