Home | History | Annotate | Download | only in gpio
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright 2016 Freescale Semiconductor, Inc.
      4  *
      5  * RGPIO2P driver for the Freescale i.MX7ULP.
      6  */
      7 
      8 #include <common.h>
      9 #include <dm.h>
     10 #include <errno.h>
     11 #include <fdtdec.h>
     12 #include <asm/gpio.h>
     13 #include <asm/io.h>
     14 #include <malloc.h>
     15 
     16 enum imx_rgpio2p_direction {
     17 	IMX_RGPIO2P_DIRECTION_IN,
     18 	IMX_RGPIO2P_DIRECTION_OUT,
     19 };
     20 
     21 #define GPIO_PER_BANK			32
     22 
     23 struct imx_rgpio2p_data {
     24 	struct gpio_regs *regs;
     25 };
     26 
     27 struct imx_rgpio2p_plat {
     28 	int bank_index;
     29 	struct gpio_regs *regs;
     30 };
     31 
     32 static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset)
     33 {
     34 	u32 val;
     35 
     36 	val = readl(&regs->gpio_pddr);
     37 
     38 	return val & (1 << offset) ? 1 : 0;
     39 }
     40 
     41 static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset,
     42 				    enum imx_rgpio2p_direction direction)
     43 {
     44 	u32 l;
     45 
     46 	l = readl(&regs->gpio_pddr);
     47 
     48 	switch (direction) {
     49 	case IMX_RGPIO2P_DIRECTION_OUT:
     50 		l |= 1 << offset;
     51 		break;
     52 	case IMX_RGPIO2P_DIRECTION_IN:
     53 		l &= ~(1 << offset);
     54 	}
     55 	writel(l, &regs->gpio_pddr);
     56 }
     57 
     58 static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset,
     59 				    int value)
     60 {
     61 	if (value)
     62 		writel((1 << offset), &regs->gpio_psor);
     63 	else
     64 		writel((1 << offset), &regs->gpio_pcor);
     65 }
     66 
     67 static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset)
     68 {
     69 	return (readl(&regs->gpio_pdir) >> offset) & 0x01;
     70 }
     71 
     72 static int  imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset)
     73 {
     74 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
     75 
     76 	/* Configure GPIO direction as input. */
     77 	imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN);
     78 
     79 	return 0;
     80 }
     81 
     82 static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset,
     83 				       int value)
     84 {
     85 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
     86 
     87 	/* Configure GPIO output value. */
     88 	imx_rgpio2p_bank_set_value(bank->regs, offset, value);
     89 
     90 	/* Configure GPIO direction as output. */
     91 	imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT);
     92 
     93 	return 0;
     94 }
     95 
     96 static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset)
     97 {
     98 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
     99 
    100 	return imx_rgpio2p_bank_get_value(bank->regs, offset);
    101 }
    102 
    103 static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset,
    104 				 int value)
    105 {
    106 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
    107 
    108 	imx_rgpio2p_bank_set_value(bank->regs, offset, value);
    109 
    110 	return 0;
    111 }
    112 
    113 static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset)
    114 {
    115 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
    116 
    117 	/* GPIOF_FUNC is not implemented yet */
    118 	if (imx_rgpio2p_is_output(bank->regs, offset))
    119 		return GPIOF_OUTPUT;
    120 	else
    121 		return GPIOF_INPUT;
    122 }
    123 
    124 static const struct dm_gpio_ops imx_rgpio2p_ops = {
    125 	.direction_input	= imx_rgpio2p_direction_input,
    126 	.direction_output	= imx_rgpio2p_direction_output,
    127 	.get_value		= imx_rgpio2p_get_value,
    128 	.set_value		= imx_rgpio2p_set_value,
    129 	.get_function		= imx_rgpio2p_get_function,
    130 };
    131 
    132 static int imx_rgpio2p_probe(struct udevice *dev)
    133 {
    134 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
    135 	struct imx_rgpio2p_plat *plat = dev_get_platdata(dev);
    136 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
    137 	int banknum;
    138 	char name[18], *str;
    139 
    140 	banknum = plat->bank_index;
    141 	sprintf(name, "GPIO%d_", banknum + 1);
    142 	str = strdup(name);
    143 	if (!str)
    144 		return -ENOMEM;
    145 	uc_priv->bank_name = str;
    146 	uc_priv->gpio_count = GPIO_PER_BANK;
    147 	bank->regs = plat->regs;
    148 
    149 	return 0;
    150 }
    151 
    152 static int imx_rgpio2p_bind(struct udevice *dev)
    153 {
    154 	struct imx_rgpio2p_plat *plat = dev->platdata;
    155 	fdt_addr_t addr;
    156 
    157 	/*
    158 	 * If platdata already exsits, directly return.
    159 	 * Actually only when DT is not supported, platdata
    160 	 * is statically initialized in U_BOOT_DEVICES.Here
    161 	 * will return.
    162 	 */
    163 	if (plat)
    164 		return 0;
    165 
    166 	addr = devfdt_get_addr_index(dev, 1);
    167 	if (addr == FDT_ADDR_T_NONE)
    168 		return -EINVAL;
    169 
    170 	/*
    171 	 * TODO:
    172 	 * When every board is converted to driver model and DT is supported,
    173 	 * this can be done by auto-alloc feature, but not using calloc
    174 	 * to alloc memory for platdata.
    175 	 *
    176 	 * For example imx_rgpio2p_plat uses platform data rather than device
    177 	 * tree.
    178 	 *
    179 	 * NOTE: DO NOT COPY this code if you are using device tree.
    180 	 */
    181 	plat = calloc(1, sizeof(*plat));
    182 	if (!plat)
    183 		return -ENOMEM;
    184 
    185 	plat->regs = (struct gpio_regs *)addr;
    186 	plat->bank_index = dev->req_seq;
    187 	dev->platdata = plat;
    188 
    189 	return 0;
    190 }
    191 
    192 
    193 static const struct udevice_id imx_rgpio2p_ids[] = {
    194 	{ .compatible = "fsl,imx7ulp-gpio" },
    195 	{ }
    196 };
    197 
    198 U_BOOT_DRIVER(imx_rgpio2p) = {
    199 	.name	= "imx_rgpio2p",
    200 	.id	= UCLASS_GPIO,
    201 	.ops	= &imx_rgpio2p_ops,
    202 	.probe	= imx_rgpio2p_probe,
    203 	.priv_auto_alloc_size = sizeof(struct imx_rgpio2p_plat),
    204 	.of_match = imx_rgpio2p_ids,
    205 	.bind	= imx_rgpio2p_bind,
    206 };
    207 
    208 #if !CONFIG_IS_ENABLED(OF_CONTROL)
    209 static const struct imx_rgpio2p_plat imx_plat[] = {
    210 	{ 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR },
    211 	{ 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR },
    212 	{ 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR },
    213 	{ 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR },
    214 	{ 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR },
    215 	{ 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR },
    216 };
    217 
    218 U_BOOT_DEVICES(imx_rgpio2ps) = {
    219 	{ "imx_rgpio2p", &imx_plat[0] },
    220 	{ "imx_rgpio2p", &imx_plat[1] },
    221 	{ "imx_rgpio2p", &imx_plat[2] },
    222 	{ "imx_rgpio2p", &imx_plat[3] },
    223 	{ "imx_rgpio2p", &imx_plat[4] },
    224 	{ "imx_rgpio2p", &imx_plat[5] },
    225 };
    226 #endif
    227