Add driver model support with this driver. In this case the platform data
is in the driver. It would be better to put this into an SOC-specific file,
but this is best attempted when more boards are moved over to use driver
model.
Signed-off-by: Simon Glass s...@chromium.org
---
Changes in v3:
- Use gpio_is_requested() in one more place
Changes in v2:
- Add an internal function to check if a GPIO is requested
- Change 'reserved' to 'requested'
- Tidy up confusing code that creates names for gpio_request()
drivers/gpio/mxc_gpio.c | 304 +++-
1 file changed, 303 insertions(+), 1 deletion(-)
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 6a572d5..3f7b7d2 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -8,16 +8,31 @@
* SPDX-License-Identifier:GPL-2.0+
*/
#include common.h
+#include errno.h
+#include dm.h
+#include malloc.h
#include asm/arch/imx-regs.h
#include asm/gpio.h
#include asm/io.h
-#include errno.h
enum mxc_gpio_direction {
MXC_GPIO_DIRECTION_IN,
MXC_GPIO_DIRECTION_OUT,
};
+#define GPIO_NAME_SIZE 20
+#define GPIO_PER_BANK 32
+
+struct mxc_gpio_plat {
+ struct gpio_regs *regs;
+};
+
+struct mxc_bank_info {
+ char label[GPIO_PER_BANK][GPIO_NAME_SIZE];
+ struct gpio_regs *regs;
+};
+
+#ifndef CONFIG_DM_GPIO
#define GPIO_TO_PORT(n)(n / 32)
/* GPIO port description */
@@ -134,3 +149,290 @@ int gpio_direction_output(unsigned gpio, int value)
return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT);
}
+#endif
+
+#ifdef CONFIG_DM_GPIO
+/**
+ * gpio_is_requested() - check if a GPIO has been requested
+ *
+ * @bank: Bank to check
+ * @offset:GPIO offset within bank to check
+ * @return true if marked as requested, false if not
+ */
+static inline bool gpio_is_requested(struct mxc_bank_info *bank, int offset)
+{
+ return *bank-label[offset] != '\0';
+}
+
+static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
+{
+ u32 val;
+
+ val = readl(regs-gpio_dir);
+
+ return val (1 offset) ? 1 : 0;
+}
+
+static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset,
+ enum mxc_gpio_direction direction)
+{
+ u32 l;
+
+ l = readl(regs-gpio_dir);
+
+ switch (direction) {
+ case MXC_GPIO_DIRECTION_OUT:
+ l |= 1 offset;
+ break;
+ case MXC_GPIO_DIRECTION_IN:
+ l = ~(1 offset);
+ }
+ writel(l, regs-gpio_dir);
+}
+
+static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
+ int value)
+{
+ u32 l;
+
+ l = readl(regs-gpio_dr);
+ if (value)
+ l |= 1 offset;
+ else
+ l = ~(1 offset);
+ writel(l, regs-gpio_dr);
+}
+
+static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
+{
+ return (readl(regs-gpio_psr) offset) 0x01;
+}
+
+static int mxc_gpio_bank_get_output_value(struct gpio_regs *regs, int offset)
+{
+ return (readl(regs-gpio_dr) offset) 0x01;
+}
+
+static int check_requested(struct udevice *dev, unsigned offset,
+ const char *func)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev-uclass_priv;
+
+ if (!gpio_is_requested(bank, offset)) {
+ printf(mxc_gpio: %s: error: gpio %s%d not requested\n,
+ func, uc_priv-bank_name, offset);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an input */
+static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+ int ret;
+
+ ret = check_requested(dev, offset, __func__);
+ if (ret)
+ return ret;
+
+ /* Configure GPIO direction as input. */
+ mxc_gpio_bank_direction(bank-regs, offset, MXC_GPIO_DIRECTION_IN);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+ int ret;
+
+ ret = check_requested(dev, offset, __func__);
+ if (ret)
+ return ret;
+
+ /* Configure GPIO output value. */
+ mxc_gpio_bank_set_value(bank-regs, offset, value);
+
+ /* Configure GPIO direction as output. */
+ mxc_gpio_bank_direction(bank-regs, offset, MXC_GPIO_DIRECTION_OUT);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int mxc_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+ int ret;
+
+ ret = check_requested(dev, offset, __func__);
+ if (ret)
+