@@ -32,6 +32,8 @@ source "drivers/spi/Kconfig"
source "drivers/gpio/Kconfig"
+source "drivers/pinctrl/Kconfig"
+
source "drivers/power/Kconfig"
source "drivers/hwmon/Kconfig"
@@ -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/
new file mode 100644
@@ -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.
new file mode 100644
@@ -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
new file mode 100644
@@ -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,
+};
@@ -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 */
new file mode 100644
@@ -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
@@ -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/
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