Message ID | 1451916117.27601.129.camel@microchip.com |
---|---|
State | Superseded |
Delegated to: | Daniel Schwierzeck |
Headers | show |
2016-01-04 15:01 GMT+01:00 Purna Chandra Mandal <purna.mandal@microchip.com>: > PIC32 has ten independently programmable ports and each with multiple pins. > These pins can be configured and used as GPIO, if not use by any other > peripherals. > > Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com> > --- > > Changes in v2: None > > drivers/gpio/Kconfig | 7 ++ > drivers/gpio/Makefile | 2 +- > drivers/gpio/pic32_gpio.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 172 insertions(+), 1 deletion(-) > create mode 100644 drivers/gpio/pic32_gpio.c > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index e60e9fd..13e9a6a 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -83,4 +83,11 @@ config VYBRID_GPIO > help > Say yes here to support Vybrid vf610 GPIOs. > > +config PIC32_GPIO > + bool "Microchip PIC32 GPIO driver" > + depends on DM_GPIO > + default y if MACH_PIC32 > + help > + Say yes here to support Microchip PIC32 GPIOs. > + > endmenu > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index fb4fd25..845a6d4 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -46,4 +46,4 @@ obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o > obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o > obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o > obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o > - > +obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o > diff --git a/drivers/gpio/pic32_gpio.c b/drivers/gpio/pic32_gpio.c > new file mode 100644 > index 0000000..69e3620 > --- /dev/null > +++ b/drivers/gpio/pic32_gpio.c > @@ -0,0 +1,164 @@ > +/* > + * Copyright (c) 2015 Microchip Technology Inc > + * Purna Chandra Mandal <purna.mandal@microchip.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <errno.h> > +#include <malloc.h> > +#include <asm/io.h> > +#include <asm/gpio.h> > +#include <linux/compat.h> > +#include <dt-bindings/gpio/gpio.h> > +#include <mach/pic32.h> > + > +/* Peripheral Pin Control */ > +struct pic32_gpio_regs { > + struct pic32_reg_atomic ansel; > + struct pic32_reg_atomic tris; > + struct pic32_reg_atomic port; > + struct pic32_reg_atomic lat; > + struct pic32_reg_atomic open_drain; > + struct pic32_reg_atomic cnpu; > + struct pic32_reg_atomic cnpd; > + struct pic32_reg_atomic cncon; > +}; > + > +enum { > + MICROCHIP_GPIO_DIR_OUT, > + MICROCHIP_GPIO_DIR_IN, > + MICROCHIP_GPIOS_PER_BANK = 16, > +}; > + > +struct pic32_gpio_priv { > + struct pic32_gpio_regs *regs; > + char name[2]; > +}; > + > +static int pic32_gpio_get_value(struct udevice *dev, unsigned offset) > +{ > + struct pic32_gpio_priv *priv = dev_get_priv(dev); > + > + return !!(readl(&priv->regs->port.raw) & BIT(offset)); > +} > + > +static int pic32_gpio_set_value(struct udevice *dev, unsigned offset, > + int value) > +{ > + struct pic32_gpio_priv *priv = dev_get_priv(dev); > + int mask = BIT(offset); > + > + if (value) > + writel(mask, &priv->regs->port.set); > + else > + writel(mask, &priv->regs->port.clr); > + > + return 0; > +} > + > +static int pic32_gpio_direction(struct udevice *dev, unsigned offset) > +{ > + struct pic32_gpio_priv *priv = dev_get_priv(dev); > + > + if (readl(&priv->regs->ansel.raw) & BIT(offset)) > + return -1; > + > + if (readl(&priv->regs->tris.raw) & BIT(offset)) > + return MICROCHIP_GPIO_DIR_IN; > + else > + return MICROCHIP_GPIO_DIR_OUT; > +} > + > +static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset) > +{ > + struct pic32_gpio_priv *priv = dev_get_priv(dev); > + int mask = BIT(offset); > + > + writel(mask, &priv->regs->ansel.clr); > + writel(mask, &priv->regs->tris.set); > + > + return 0; > +} > + > +static int pic32_gpio_direction_output(struct udevice *dev, > + unsigned offset, int value) > +{ > + struct pic32_gpio_priv *priv = dev_get_priv(dev); > + int mask = BIT(offset); > + > + writel(mask, &priv->regs->ansel.clr); > + writel(mask, &priv->regs->tris.clr); > + > + pic32_gpio_set_value(dev, offset, value); > + return 0; > +} > + > +static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, > + struct fdtdec_phandle_args *args) > +{ > + desc->offset = args->args[0]; > + desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; > + > + return 0; > +} > + > +static int pic32_gpio_probe(struct udevice *dev) > +{ > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > + struct pic32_gpio_priv *priv = dev_get_priv(dev); > + char *end; > + int bank; > + > + priv->regs = pic32_ioremap(dev_get_addr(dev)); split this code and check the return value of dev_get_addr for FDT_ADDR_T_NONE like you did in your other drivers. > + uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK; > + end = strrchr(dev->name, '@'); > + bank = trailing_strtoln(dev->name, end); > + priv->name[0] = 'A' + bank; > + uc_priv->bank_name = priv->name; > + > + return 0; > +} > + > +static int pic32_gpio_get_function(struct udevice *dev, unsigned offset) > +{ > + int ret = GPIOF_UNUSED; > + > + switch (pic32_gpio_direction(dev, offset)) { > + case MICROCHIP_GPIO_DIR_OUT: > + ret = GPIOF_OUTPUT; > + break; > + case MICROCHIP_GPIO_DIR_IN: > + ret = GPIOF_INPUT; > + break; > + default: > + ret = GPIOF_UNUSED; > + break; > + } > + return ret; > +} > + > +static const struct dm_gpio_ops gpio_pic32_ops = { > + .direction_input = pic32_gpio_direction_input, > + .direction_output = pic32_gpio_direction_output, > + .get_value = pic32_gpio_get_value, > + .set_value = pic32_gpio_set_value, > + .get_function = pic32_gpio_get_function, > + .xlate = pic32_gpio_xlate, > +}; > + > +static const struct udevice_id pic32_gpio_ids[] = { > + { .compatible = "microchip,pic32mzda-gpio" }, > + { } > +}; > + > +U_BOOT_DRIVER(gpio_pic32) = { > + .name = "gpio_pic32", > + .id = UCLASS_GPIO, > + .of_match = pic32_gpio_ids, > + .ops = &gpio_pic32_ops, > + .probe = pic32_gpio_probe, > + .priv_auto_alloc_size = sizeof(struct pic32_gpio_priv), > +}; > -- > 1.8.3.1 > >
On 01/06/2016 02:13 AM, Daniel Schwierzeck wrote: > 2016-01-04 15:01 GMT+01:00 Purna Chandra Mandal <purna.mandal@microchip.com>: >> PIC32 has ten independently programmable ports and each with multiple pins. >> These pins can be configured and used as GPIO, if not use by any other >> peripherals. >> >> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com> >> --- >> >> Changes in v2: None >> >> drivers/gpio/Kconfig | 7 ++ >> drivers/gpio/Makefile | 2 +- >> drivers/gpio/pic32_gpio.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 172 insertions(+), 1 deletion(-) >> create mode 100644 drivers/gpio/pic32_gpio.c >> >> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig >> index e60e9fd..13e9a6a 100644 >> --- a/drivers/gpio/Kconfig >> +++ b/drivers/gpio/Kconfig >> @@ -83,4 +83,11 @@ config VYBRID_GPIO >> help >> Say yes here to support Vybrid vf610 GPIOs. >> >> +config PIC32_GPIO >> + bool "Microchip PIC32 GPIO driver" >> + depends on DM_GPIO >> + default y if MACH_PIC32 >> + help >> + Say yes here to support Microchip PIC32 GPIOs. >> + >> endmenu >> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile >> index fb4fd25..845a6d4 100644 >> --- a/drivers/gpio/Makefile >> +++ b/drivers/gpio/Makefile >> @@ -46,4 +46,4 @@ obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o >> obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o >> obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o >> obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o >> - >> +obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o >> diff --git a/drivers/gpio/pic32_gpio.c b/drivers/gpio/pic32_gpio.c >> new file mode 100644 >> index 0000000..69e3620 >> --- /dev/null >> +++ b/drivers/gpio/pic32_gpio.c >> @@ -0,0 +1,164 @@ >> +/* >> + * Copyright (c) 2015 Microchip Technology Inc >> + * Purna Chandra Mandal <purna.mandal@microchip.com> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> + >> +#include <common.h> >> +#include <dm.h> >> +#include <errno.h> >> +#include <malloc.h> >> +#include <asm/io.h> >> +#include <asm/gpio.h> >> +#include <linux/compat.h> >> +#include <dt-bindings/gpio/gpio.h> >> +#include <mach/pic32.h> >> + >> +/* Peripheral Pin Control */ >> +struct pic32_gpio_regs { >> + struct pic32_reg_atomic ansel; >> + struct pic32_reg_atomic tris; >> + struct pic32_reg_atomic port; >> + struct pic32_reg_atomic lat; >> + struct pic32_reg_atomic open_drain; >> + struct pic32_reg_atomic cnpu; >> + struct pic32_reg_atomic cnpd; >> + struct pic32_reg_atomic cncon; >> +}; >> + >> +enum { >> + MICROCHIP_GPIO_DIR_OUT, >> + MICROCHIP_GPIO_DIR_IN, >> + MICROCHIP_GPIOS_PER_BANK = 16, >> +}; >> + >> +struct pic32_gpio_priv { >> + struct pic32_gpio_regs *regs; >> + char name[2]; >> +}; >> + >> +static int pic32_gpio_get_value(struct udevice *dev, unsigned offset) >> +{ >> + struct pic32_gpio_priv *priv = dev_get_priv(dev); >> + >> + return !!(readl(&priv->regs->port.raw) & BIT(offset)); >> +} >> + >> +static int pic32_gpio_set_value(struct udevice *dev, unsigned offset, >> + int value) >> +{ >> + struct pic32_gpio_priv *priv = dev_get_priv(dev); >> + int mask = BIT(offset); >> + >> + if (value) >> + writel(mask, &priv->regs->port.set); >> + else >> + writel(mask, &priv->regs->port.clr); >> + >> + return 0; >> +} >> + >> +static int pic32_gpio_direction(struct udevice *dev, unsigned offset) >> +{ >> + struct pic32_gpio_priv *priv = dev_get_priv(dev); >> + >> + if (readl(&priv->regs->ansel.raw) & BIT(offset)) >> + return -1; >> + >> + if (readl(&priv->regs->tris.raw) & BIT(offset)) >> + return MICROCHIP_GPIO_DIR_IN; >> + else >> + return MICROCHIP_GPIO_DIR_OUT; >> +} >> + >> +static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset) >> +{ >> + struct pic32_gpio_priv *priv = dev_get_priv(dev); >> + int mask = BIT(offset); >> + >> + writel(mask, &priv->regs->ansel.clr); >> + writel(mask, &priv->regs->tris.set); >> + >> + return 0; >> +} >> + >> +static int pic32_gpio_direction_output(struct udevice *dev, >> + unsigned offset, int value) >> +{ >> + struct pic32_gpio_priv *priv = dev_get_priv(dev); >> + int mask = BIT(offset); >> + >> + writel(mask, &priv->regs->ansel.clr); >> + writel(mask, &priv->regs->tris.clr); >> + >> + pic32_gpio_set_value(dev, offset, value); >> + return 0; >> +} >> + >> +static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, >> + struct fdtdec_phandle_args *args) >> +{ >> + desc->offset = args->args[0]; >> + desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; >> + >> + return 0; >> +} >> + >> +static int pic32_gpio_probe(struct udevice *dev) >> +{ >> + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); >> + struct pic32_gpio_priv *priv = dev_get_priv(dev); >> + char *end; >> + int bank; >> + >> + priv->regs = pic32_ioremap(dev_get_addr(dev)); > split this code and check the return value of dev_get_addr for > FDT_ADDR_T_NONE like you did in your other drivers. Ack, Will add sanity check. >> + uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK; >> + end = strrchr(dev->name, '@'); >> + bank = trailing_strtoln(dev->name, end); >> + priv->name[0] = 'A' + bank; >> + uc_priv->bank_name = priv->name; >> + >> + return 0; >> +} >> + >> +static int pic32_gpio_get_function(struct udevice *dev, unsigned offset) >> +{ >> + int ret = GPIOF_UNUSED; >> + >> + switch (pic32_gpio_direction(dev, offset)) { >> + case MICROCHIP_GPIO_DIR_OUT: >> + ret = GPIOF_OUTPUT; >> + break; >> + case MICROCHIP_GPIO_DIR_IN: >> + ret = GPIOF_INPUT; >> + break; >> + default: >> + ret = GPIOF_UNUSED; >> + break; >> + } >> + return ret; >> +} >> + >> +static const struct dm_gpio_ops gpio_pic32_ops = { >> + .direction_input = pic32_gpio_direction_input, >> + .direction_output = pic32_gpio_direction_output, >> + .get_value = pic32_gpio_get_value, >> + .set_value = pic32_gpio_set_value, >> + .get_function = pic32_gpio_get_function, >> + .xlate = pic32_gpio_xlate, >> +}; >> + >> +static const struct udevice_id pic32_gpio_ids[] = { >> + { .compatible = "microchip,pic32mzda-gpio" }, >> + { } >> +}; >> + >> +U_BOOT_DRIVER(gpio_pic32) = { >> + .name = "gpio_pic32", >> + .id = UCLASS_GPIO, >> + .of_match = pic32_gpio_ids, >> + .ops = &gpio_pic32_ops, >> + .probe = pic32_gpio_probe, >> + .priv_auto_alloc_size = sizeof(struct pic32_gpio_priv), >> +}; >> -- >> 1.8.3.1 >> >> > >
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e60e9fd..13e9a6a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -83,4 +83,11 @@ config VYBRID_GPIO help Say yes here to support Vybrid vf610 GPIOs. +config PIC32_GPIO + bool "Microchip PIC32 GPIO driver" + depends on DM_GPIO + default y if MACH_PIC32 + help + Say yes here to support Microchip PIC32 GPIOs. + endmenu diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fb4fd25..845a6d4 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -46,4 +46,4 @@ obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o - +obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o diff --git a/drivers/gpio/pic32_gpio.c b/drivers/gpio/pic32_gpio.c new file mode 100644 index 0000000..69e3620 --- /dev/null +++ b/drivers/gpio/pic32_gpio.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015 Microchip Technology Inc + * Purna Chandra Mandal <purna.mandal@microchip.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <linux/compat.h> +#include <dt-bindings/gpio/gpio.h> +#include <mach/pic32.h> + +/* Peripheral Pin Control */ +struct pic32_gpio_regs { + struct pic32_reg_atomic ansel; + struct pic32_reg_atomic tris; + struct pic32_reg_atomic port; + struct pic32_reg_atomic lat; + struct pic32_reg_atomic open_drain; + struct pic32_reg_atomic cnpu; + struct pic32_reg_atomic cnpd; + struct pic32_reg_atomic cncon; +}; + +enum { + MICROCHIP_GPIO_DIR_OUT, + MICROCHIP_GPIO_DIR_IN, + MICROCHIP_GPIOS_PER_BANK = 16, +}; + +struct pic32_gpio_priv { + struct pic32_gpio_regs *regs; + char name[2]; +}; + +static int pic32_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct pic32_gpio_priv *priv = dev_get_priv(dev); + + return !!(readl(&priv->regs->port.raw) & BIT(offset)); +} + +static int pic32_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct pic32_gpio_priv *priv = dev_get_priv(dev); + int mask = BIT(offset); + + if (value) + writel(mask, &priv->regs->port.set); + else + writel(mask, &priv->regs->port.clr); + + return 0; +} + +static int pic32_gpio_direction(struct udevice *dev, unsigned offset) +{ + struct pic32_gpio_priv *priv = dev_get_priv(dev); + + if (readl(&priv->regs->ansel.raw) & BIT(offset)) + return -1; + + if (readl(&priv->regs->tris.raw) & BIT(offset)) + return MICROCHIP_GPIO_DIR_IN; + else + return MICROCHIP_GPIO_DIR_OUT; +} + +static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct pic32_gpio_priv *priv = dev_get_priv(dev); + int mask = BIT(offset); + + writel(mask, &priv->regs->ansel.clr); + writel(mask, &priv->regs->tris.set); + + return 0; +} + +static int pic32_gpio_direction_output(struct udevice *dev, + unsigned offset, int value) +{ + struct pic32_gpio_priv *priv = dev_get_priv(dev); + int mask = BIT(offset); + + writel(mask, &priv->regs->ansel.clr); + writel(mask, &priv->regs->tris.clr); + + pic32_gpio_set_value(dev, offset, value); + return 0; +} + +static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct fdtdec_phandle_args *args) +{ + desc->offset = args->args[0]; + desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; + + return 0; +} + +static int pic32_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct pic32_gpio_priv *priv = dev_get_priv(dev); + char *end; + int bank; + + priv->regs = pic32_ioremap(dev_get_addr(dev)); + uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK; + end = strrchr(dev->name, '@'); + bank = trailing_strtoln(dev->name, end); + priv->name[0] = 'A' + bank; + uc_priv->bank_name = priv->name; + + return 0; +} + +static int pic32_gpio_get_function(struct udevice *dev, unsigned offset) +{ + int ret = GPIOF_UNUSED; + + switch (pic32_gpio_direction(dev, offset)) { + case MICROCHIP_GPIO_DIR_OUT: + ret = GPIOF_OUTPUT; + break; + case MICROCHIP_GPIO_DIR_IN: + ret = GPIOF_INPUT; + break; + default: + ret = GPIOF_UNUSED; + break; + } + return ret; +} + +static const struct dm_gpio_ops gpio_pic32_ops = { + .direction_input = pic32_gpio_direction_input, + .direction_output = pic32_gpio_direction_output, + .get_value = pic32_gpio_get_value, + .set_value = pic32_gpio_set_value, + .get_function = pic32_gpio_get_function, + .xlate = pic32_gpio_xlate, +}; + +static const struct udevice_id pic32_gpio_ids[] = { + { .compatible = "microchip,pic32mzda-gpio" }, + { } +}; + +U_BOOT_DRIVER(gpio_pic32) = { + .name = "gpio_pic32", + .id = UCLASS_GPIO, + .of_match = pic32_gpio_ids, + .ops = &gpio_pic32_ops, + .probe = pic32_gpio_probe, + .priv_auto_alloc_size = sizeof(struct pic32_gpio_priv), +};
PIC32 has ten independently programmable ports and each with multiple pins. These pins can be configured and used as GPIO, if not use by any other peripherals. Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com> --- Changes in v2: None drivers/gpio/Kconfig | 7 ++ drivers/gpio/Makefile | 2 +- drivers/gpio/pic32_gpio.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 drivers/gpio/pic32_gpio.c