Am Dienstag, den 12.01.2016, 15:48 +0530 schrieb Purna Chandra Mandal: > In PIC32 pin-controller is a combined gpio-controller, pin-mux and > pin-config module. Remappable peripherals are assigned pins through > per-pin based muxing logic. And pin configuration are performed on > specific port registers which are shared along with gpio controller. > Note, non-remappable peripherals have default pins assigned thus > require > no muxing. > > Signed-off-by: Purna Chandra Mandal <purna.man...@microchip.com> >
Reviewed-by: Daniel Schwierzeck <daniel.schwierz...@gmail.com> > > --- > > Changes in v3: > - read register base from device-tree > - add/update comments to explain how pinctrl'r works. > - replace pic32_ioremap() with ioremap(). > > Changes in v2: > - add pinconf routine for configuring pin property > > drivers/pinctrl/Kconfig | 9 + > drivers/pinctrl/Makefile | 1 + > drivers/pinctrl/pinctrl_pic32.c | 363 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 373 insertions(+) > create mode 100644 drivers/pinctrl/pinctrl_pic32.c > > diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig > index 57e6142..292c4e2 100644 > --- a/drivers/pinctrl/Kconfig > +++ b/drivers/pinctrl/Kconfig > @@ -131,6 +131,15 @@ config PINCTRL_SANDBOX > actually does nothing but print debug messages when > pinctrl > operations are invoked. > > +config PIC32_PINCTRL > + bool "Microchip PIC32 pin-control and pin-mux driver" > + depends on DM && MACH_PIC32 > + help > + Supports individual pin selection and configuration for > each remappable > + peripheral available on Microchip PIC32 SoCs. This driver > is controlled > + by a device tree node which contains both GPIO defintion > and pin control > + functions. > + > endif > > source "drivers/pinctrl/uniphier/Kconfig" > diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile > index 70d25dc..b4f4650 100644 > --- a/drivers/pinctrl/Makefile > +++ b/drivers/pinctrl/Makefile > @@ -9,3 +9,4 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ > obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o > > obj-$(CONFIG_ARCH_UNIPHIER) += uniphier/ > +obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o > diff --git a/drivers/pinctrl/pinctrl_pic32.c > b/drivers/pinctrl/pinctrl_pic32.c > new file mode 100644 > index 0000000..5cf97ec > --- /dev/null > +++ b/drivers/pinctrl/pinctrl_pic32.c > @@ -0,0 +1,363 @@ > +/* > + * Pinctrl driver for Microchip PIC32 SoCs > + * Copyright (c) 2015 Microchip Technology Inc. > + * Written by Purna Chandra Mandal <purna.man...@microchip.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#include <common.h> > +#include <dm.h> > +#include <errno.h> > +#include <asm/io.h> > +#include <dm/pinctrl.h> > +#include <dm/root.h> > +#include <mach/pic32.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +/* PIC32 has 10 peripheral ports with 16 pins each. > + * Ports are marked PORTA-PORTK or PORT0-PORT9. > + */ > +enum { > + PIC32_PORT_A = 0, > + PIC32_PORT_B = 1, > + PIC32_PORT_C = 2, > + PIC32_PORT_D = 3, > + PIC32_PORT_E = 4, > + PIC32_PORT_F = 5, > + PIC32_PORT_G = 6, > + PIC32_PORT_H = 7, > + PIC32_PORT_J = 8, /* no PORT_I */ > + PIC32_PORT_K = 9, > + PIC32_PINS_PER_PORT = 16, > +}; > + > +#define PIN_CONFIG_PIC32_DIGITAL (PIN_CONFIG_END + 1) > +#define PIN_CONFIG_PIC32_ANALOG (PIN_CONFIG_END + 2) > + > +/* pin configuration descriptor */ > +struct pic32_pin_config { > + u16 port; /* port number */ > + u16 pin; /* pin number in the port */ > + u32 config; /* one of PIN_CONFIG_* */ > +}; > +#define PIN_CONFIG(_prt, _pin, _cfg) \ > + {.port = (_prt), .pin = (_pin), .config = (_cfg), } > + > +/* In PIC32 muxing is performed at pin-level through two > + * different set of registers - one set for input functions, > + * and other for output functions. > + * Pin configuration is handled through port register. > + */ > +/* Port control registers */ > +struct pic32_reg_port { > + struct pic32_reg_atomic ansel; > + struct pic32_reg_atomic tris; > + struct pic32_reg_atomic port; > + struct pic32_reg_atomic lat; > + struct pic32_reg_atomic odc; > + struct pic32_reg_atomic cnpu; > + struct pic32_reg_atomic cnpd; > + struct pic32_reg_atomic cncon; > + struct pic32_reg_atomic unused[8]; > +}; > + > +/* Input function mux registers */ > +struct pic32_reg_in_mux { > + u32 unused0; > + u32 int1[4]; > + u32 unused1; > + u32 t2ck[8]; > + u32 ic1[9]; > + u32 unused2; > + u32 ocfar; > + u32 unused3; > + u32 u1rx; > + u32 u1cts; > + u32 u2rx; > + u32 u2cts; > + u32 u3rx; > + u32 u3cts; > + u32 u4rx; > + u32 u4cts; > + u32 u5rx; > + u32 u5cts; > + u32 u6rx; > + u32 u6cts; > + u32 unused4; > + u32 sdi1; > + u32 ss1; > + u32 unused5; > + u32 sdi2; > + u32 ss2; > + u32 unused6; > + u32 sdi3; > + u32 ss3; > + u32 unused7; > + u32 sdi4; > + u32 ss4; > + u32 unused8; > + u32 sdi5; > + u32 ss5; > + u32 unused9; > + u32 sdi6; > + u32 ss6; > + u32 c1rx; > + u32 c2rx; > + u32 refclki1; > + u32 refclki2; > + u32 refclki3; > + u32 refclki4; > +}; > + > +/* output mux register offset */ > +#define PPS_OUT(__port, __pin) \ > + (((__port) * PIC32_PINS_PER_PORT + (__pin)) << 2) > + > + > +struct pic32_pinctrl_priv { > + struct pic32_reg_in_mux *mux_in; /* mux input function */ > + struct pic32_reg_port *pinconf; /* pin configuration*/ > + void __iomem *mux_out; /* mux output function */ > +}; > + > +enum { > + PERIPH_ID_UART1, > + PERIPH_ID_UART2, > + PERIPH_ID_ETH, > + PERIPH_ID_USB, > + PERIPH_ID_SDHCI, > + PERIPH_ID_I2C1, > + PERIPH_ID_I2C2, > + PERIPH_ID_SPI1, > + PERIPH_ID_SPI2, > + PERIPH_ID_SQI, > +}; > + > +static int pic32_pinconfig_one(struct pic32_pinctrl_priv *priv, > + u32 port_nr, u32 pin, u32 param) > +{ > + struct pic32_reg_port *port; > + > + port = &priv->pinconf[port_nr]; > + switch (param) { > + case PIN_CONFIG_PIC32_DIGITAL: > + writel(BIT(pin), &port->ansel.clr); > + break; > + case PIN_CONFIG_PIC32_ANALOG: > + writel(BIT(pin), &port->ansel.set); > + break; > + case PIN_CONFIG_INPUT_ENABLE: > + writel(BIT(pin), &port->tris.set); > + break; > + case PIN_CONFIG_OUTPUT: > + writel(BIT(pin), &port->tris.clr); > + break; > + case PIN_CONFIG_BIAS_PULL_UP: > + writel(BIT(pin), &port->cnpu.set); > + break; > + case PIN_CONFIG_BIAS_PULL_DOWN: > + writel(BIT(pin), &port->cnpd.set); > + break; > + case PIN_CONFIG_DRIVE_OPEN_DRAIN: > + writel(BIT(pin), &port->odc.set); > + break; > + default: > + break; > + } > + > + return 0; > +} > + > +static int pic32_pinconfig_set(struct pic32_pinctrl_priv *priv, > + const struct pic32_pin_config *list, > int count) > +{ > + int i; > + > + for (i = 0 ; i < count; i++) > + pic32_pinconfig_one(priv, list[i].port, > + list[i].pin, list[i].config); > + > + return 0; > +} > + > +static void pic32_eth_pin_config(struct udevice *dev) > +{ > + struct pic32_pinctrl_priv *priv = dev_get_priv(dev); > + const struct pic32_pin_config configs[] = { > + /* EMDC - D11 */ > + PIN_CONFIG(PIC32_PORT_D, 11, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_D, 11, PIN_CONFIG_OUTPUT), > + /* ETXEN */ > + PIN_CONFIG(PIC32_PORT_D, 6, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_D, 6, PIN_CONFIG_OUTPUT), > + /* ECRSDV */ > + PIN_CONFIG(PIC32_PORT_H, 13, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_H, 13, > PIN_CONFIG_INPUT_ENABLE), > + /* ERXD0 */ > + PIN_CONFIG(PIC32_PORT_H, 8, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_H, 8, > PIN_CONFIG_INPUT_ENABLE), > + PIN_CONFIG(PIC32_PORT_H, 8, > PIN_CONFIG_BIAS_PULL_DOWN), > + /* ERXD1 */ > + PIN_CONFIG(PIC32_PORT_H, 5, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_H, 5, > PIN_CONFIG_INPUT_ENABLE), > + PIN_CONFIG(PIC32_PORT_H, 5, > PIN_CONFIG_BIAS_PULL_DOWN), > + /* EREFCLK */ > + PIN_CONFIG(PIC32_PORT_J, 11, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_J, 11, > PIN_CONFIG_INPUT_ENABLE), > + /* ETXD1 */ > + PIN_CONFIG(PIC32_PORT_J, 9, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_J, 9, PIN_CONFIG_OUTPUT), > + /* ETXD0 */ > + PIN_CONFIG(PIC32_PORT_J, 8, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_J, 8, PIN_CONFIG_OUTPUT), > + /* EMDIO */ > + PIN_CONFIG(PIC32_PORT_J, 1, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_J, 1, > PIN_CONFIG_INPUT_ENABLE), > + /* ERXERR */ > + PIN_CONFIG(PIC32_PORT_F, 3, > PIN_CONFIG_PIC32_DIGITAL), > + PIN_CONFIG(PIC32_PORT_F, 3, > PIN_CONFIG_INPUT_ENABLE), > + }; > + > + pic32_pinconfig_set(priv, configs, ARRAY_SIZE(configs)); > +} > + > +static int pic32_pinctrl_request(struct udevice *dev, int func, int > flags) > +{ > + struct pic32_pinctrl_priv *priv = dev_get_priv(dev); > + > + switch (func) { > + case PERIPH_ID_UART2: > + /* PPS for U2 RX/TX */ > + writel(0x02, priv->mux_out + PPS_OUT(PIC32_PORT_G, > 9)); > + writel(0x05, &priv->mux_in->u2rx); /* B0 */ > + /* set digital mode */ > + pic32_pinconfig_one(priv, PIC32_PORT_G, 9, > + PIN_CONFIG_PIC32_DIGITAL); > + pic32_pinconfig_one(priv, PIC32_PORT_B, 0, > + PIN_CONFIG_PIC32_DIGITAL); > + break; > + case PERIPH_ID_ETH: > + pic32_eth_pin_config(dev); > + break; > + default: > + debug("%s: unknown-unhandled case\n", __func__); > + break; > + } > + > + return 0; > +} > + > +static int pic32_pinctrl_get_periph_id(struct udevice *dev, > + struct udevice *periph) > +{ > + int ret; > + u32 cell[2]; > + > + ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset, > + "interrupts", cell, > ARRAY_SIZE(cell)); > + if (ret < 0) > + return -EINVAL; > + > + /* interrupt number */ > + switch (cell[0]) { > + case 112 ... 114: > + return PERIPH_ID_UART1; > + case 145 ... 147: > + return PERIPH_ID_UART2; > + case 109 ... 111: > + return PERIPH_ID_SPI1; > + case 142 ... 144: > + return PERIPH_ID_SPI2; > + case 115 ... 117: > + return PERIPH_ID_I2C1; > + case 148 ... 150: > + return PERIPH_ID_I2C2; > + case 132 ... 133: > + return PERIPH_ID_USB; > + case 169: > + return PERIPH_ID_SQI; > + case 191: > + return PERIPH_ID_SDHCI; > + case 153: > + return PERIPH_ID_ETH; > + default: > + break; > + } > + > + return -ENOENT; > +} > + > +static int pic32_pinctrl_set_state_simple(struct udevice *dev, > + struct udevice *periph) > +{ > + int func; > + > + debug("%s: periph %s\n", __func__, periph->name); > + func = pic32_pinctrl_get_periph_id(dev, periph); > + if (func < 0) > + return func; > + return pic32_pinctrl_request(dev, func, 0); > +} > + > +static struct pinctrl_ops pic32_pinctrl_ops = { > + .set_state_simple = pic32_pinctrl_set_state_simple, > + .request = pic32_pinctrl_request, > + .get_periph_id = pic32_pinctrl_get_periph_id, > +}; > + > +static int pic32_pinctrl_probe(struct udevice *dev) > +{ > + struct pic32_pinctrl_priv *priv = dev_get_priv(dev); > + struct fdt_resource res; > + void *fdt = (void *)gd->fdt_blob; > + int node = dev->of_offset; > + int ret; > + > + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", > + "ppsin", &res); > + if (ret < 0) { > + printf("pinctrl: resource \"ppsin\" not found\n"); > + return ret; > + } > + priv->mux_in = ioremap(res.start, fdt_resource_size(&res)); > + > + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", > + "ppsout", &res); > + if (ret < 0) { > + printf("pinctrl: resource \"ppsout\" not found\n"); > + return ret; > + } > + priv->mux_out = ioremap(res.start, fdt_resource_size(&res)); > + > + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", > + "port", &res); > + if (ret < 0) { > + printf("pinctrl: resource \"port\" not found\n"); > + return ret; > + } > + priv->pinconf = ioremap(res.start, fdt_resource_size(&res)); > + > + return 0; > +} > + > +static int pic32_pinctrl_bind(struct udevice *dev) > +{ > + /* scan child GPIO banks */ > + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, > false); > +} > + > +static const struct udevice_id pic32_pinctrl_ids[] = { > + { .compatible = "microchip,pic32mzda-pinctrl" }, > + { } > +}; > + > +U_BOOT_DRIVER(pinctrl_pic32) = { > + .name = "pinctrl_pic32", > + .id = UCLASS_PINCTRL, > + .of_match = pic32_pinctrl_ids, > + .ops = &pic32_pinctrl_ops, > + .probe = pic32_pinctrl_probe, > + .bind = pic32_pinctrl_bind, > + .priv_auto_alloc_size = sizeof(struct pic32_pinctrl_priv), > +}; -- - Daniel _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot