
Add a uclass which permits pin multiplexing to be configured for a particular function. It uses the concept of a peripheral ID to specify the peripheral to adjust. Typically peripheral IDs are SPI0, SPI1, MMC0, etc.
The uclass provides two methods:
- get_periph_id() - returns the peripheral ID for a particular driver model device. This can be used to look up (say) an I2C device, and then find its peripheral ID so that the pins for that device can be requested.
- request() - allows a particular function to be requested. This change may impact multiple pins on the chip. For example, an I2C bus requires two pins (clock and data) and the request() method will set up both pins.
This also allows GPIO drivers which sit under the 'pinctrl' device tree node to be detected and used.
At some point this could be expanded to support a full interface with support for the full device tree bindings. In that case the concept of peripheral ID might not be needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/Kconfig | 2 ++ drivers/Makefile | 1 + drivers/pinctrl/Kconfig | 19 +++++++++++ drivers/pinctrl/Makefile | 8 +++++ drivers/pinctrl/pinctrl-uclass.c | 51 +++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/pinctrl.h | 74 ++++++++++++++++++++++++++++++++++++++++ scripts/Makefile.spl | 1 + 8 files changed, 157 insertions(+) create mode 100644 drivers/pinctrl/Kconfig create mode 100644 drivers/pinctrl/Makefile create mode 100644 drivers/pinctrl/pinctrl-uclass.c create mode 100644 include/pinctrl.h
diff --git a/drivers/Kconfig b/drivers/Kconfig index ee942e2..17a61e4 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -32,6 +32,8 @@ source "drivers/spi/Kconfig"
source "drivers/gpio/Kconfig"
+source "drivers/pinctrl/Kconfig" + source "drivers/power/Kconfig"
source "drivers/hwmon/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index c090aba..b68c4ee 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_LED) += led/ obj-y += misc/ obj-y += pcmcia/ obj-y += dfu/ +obj-$(CONFIG_PINCTRL) += pinctrl/ obj-y += rtc/ obj-y += sound/ obj-y += tpm/ diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig new file mode 100644 index 0000000..e667361 --- /dev/null +++ b/drivers/pinctrl/Kconfig @@ -0,0 +1,19 @@ +config PINCTRL + bool "Pin multiplexing driver support" + help + Support pin multiplexing control in U-Boot. Most SoCs have their own + own multiplexing arrangement where a single pin can be used for + several functions. An SoC pinctrl driver allows the required + function to be selected for each pin. The driver is typically + controlled by the device tree. + +config SPL_PINCTRL_SUPPORT + bool "Enable pin multiplexing (pinctrl) support in SPL" + depends on PINCTRL + help + The pinctrl subsystem can add a substantial overhead to the SPL + image since it typically requires quite a few tables either in the + driver or in the device tree. If this is acceptable and you need + to adjust pin multiplexing in SPL in order to boot into U-Boot, + enable this option. You will need to enable device tree in SPL + for this to work. diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile new file mode 100644 index 0000000..6e63ee7 --- /dev/null +++ b/drivers/pinctrl/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (c) 2015 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_PINCTRL) += pinctrl-uclass.o diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c new file mode 100644 index 0000000..82bd980 --- /dev/null +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <pinctrl.h> +#include <dm/root.h> + +DECLARE_GLOBAL_DATA_PTR; + +int pinctrl_request(struct udevice *dev, int func, int flags) +{ + struct pinctrl_ops *ops = pinctrl_get_ops(dev); + + if (!ops->request) + return -ENOSYS; + + return ops->request(dev, func, flags); +} + +int pinctrl_request_noflags(struct udevice *dev, int func) +{ + return pinctrl_request(dev, func, 0); +} + +int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph) +{ + struct pinctrl_ops *ops = pinctrl_get_ops(dev); + + if (!ops->get_periph_id) + return -ENOSYS; + + return ops->get_periph_id(dev, periph); +} + +static int pinctrl_post_bind(struct udevice *dev) +{ + /* Scan the bus for devices */ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + +UCLASS_DRIVER(pinctrl) = { + .id = UCLASS_PINCTRL, + .name = "pinctrl", + .post_bind = pinctrl_post_bind, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index cba7c0a..14a1614 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -41,6 +41,7 @@ enum uclass_id { UCLASS_PCH, /* x86 platform controller hub */ UCLASS_PCI, /* PCI bus */ UCLASS_PCI_GENERIC, /* Generic PCI bus device */ + UCLASS_PINCTRL, /* Pin multiplexing control */ UCLASS_PMIC, /* PMIC I/O device */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_RTC, /* Real time clock device */ diff --git a/include/pinctrl.h b/include/pinctrl.h new file mode 100644 index 0000000..e7aca2e --- /dev/null +++ b/include/pinctrl.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINCTRL_H +#define __PINCTRL_H + +struct pinctrl_ops { + /** + * request() - Request a particular pinctrl function + * + * This activates the selected function. + * + * @dev: Device to adjust (UCLASS_PINCTRL) + * @func: Function number (driver-specific) + * @return 0 if OK, -ve on error + */ + int (*request)(struct udevice *dev, int func, int flags); + + /** + * get_periph_id() - get the peripheral ID for a device + * + * This generally looks at the peripheral's device tree node to work + * out the peripheral ID. The return value is normally interpreted as + * enum periph_id. so long as this is defined by the platform (which it + * should be). + * + * @dev: Pinctrl device to use for decoding + * @periph: Device to check + * @return peripheral ID of @periph, or -ENOENT on error + */ + int (*get_periph_id)(struct udevice *dev, struct udevice *periph); +}; + +#define pinctrl_get_ops(dev) ((struct pinctrl_ops *)(dev)->driver->ops) + +/** + * pinctrl_request() - Request a particular pinctrl function + * + * @dev: Device to check (UCLASS_PINCTRL) + * @func: Function number (driver-specific) + * @flags: Flags (driver-specific) + * @return 0 if OK, -ve on error + */ +int pinctrl_request(struct udevice *dev, int func, int flags); + +/** + * pinctrl_request_noflags() - Request a particular pinctrl function + * + * This is similar to pinctrl_request() but uses 0 for @flags. + * + * @dev: Device to check (UCLASS_PINCTRL) + * @func: Function number (driver-specific) + * @return 0 if OK, -ve on error + */ +int pinctrl_request_noflags(struct udevice *dev, int func); + +/** + * pinctrl_get_periph_id() - get the peripheral ID for a device + * + * This generally looks at the peripheral's device tree node to work out the + * peripheral ID. The return value is normally interpreted as enum periph_id. + * so long as this is defined by the platform (which it should be). + * + * @dev: Pinctrl device to use for decoding + * @periph: Device to check + * @return peripheral ID of @periph, or -ENOENT on error + */ +int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph); + +#endif diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 6b32618..24ca58b 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -77,6 +77,7 @@ libs-$(CONFIG_SPL_NET_SUPPORT) += net/ libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/ libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/ libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/ +libs-$(CONFIG_SPL_PINCTRL_SUPPORT) += drivers/pinctrl/ libs-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/ libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/ libs-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/