xref: /openbmc/u-boot/drivers/gpio/altera_pio.c (revision 7b384eccc785b596f68448b155cbda26df57fb23)
1  // SPDX-License-Identifier: GPL-2.0+
2  /*
3   * Copyright (C) 2015  Thomas Chou <thomas@wytron.com.tw>
4   * Copyright (C) 2011  Missing Link Electronics
5   *                     Joachim Foerster <joachim@missinglinkelectronics.com>
6   */
7  #include <common.h>
8  #include <dm.h>
9  #include <errno.h>
10  #include <malloc.h>
11  #include <fdtdec.h>
12  #include <asm/io.h>
13  #include <asm/gpio.h>
14  
15  DECLARE_GLOBAL_DATA_PTR;
16  
17  struct altera_pio_regs {
18  	u32	data;			/* Data register */
19  	u32	direction;		/* Direction register */
20  };
21  
22  struct altera_pio_platdata {
23  	struct altera_pio_regs *regs;
24  	int gpio_count;
25  	const char *bank_name;
26  };
27  
28  static int altera_pio_direction_input(struct udevice *dev, unsigned pin)
29  {
30  	struct altera_pio_platdata *plat = dev_get_platdata(dev);
31  	struct altera_pio_regs *const regs = plat->regs;
32  
33  	clrbits_le32(&regs->direction, 1 << pin);
34  
35  	return 0;
36  }
37  
38  static int altera_pio_direction_output(struct udevice *dev, unsigned pin,
39  				     int val)
40  {
41  	struct altera_pio_platdata *plat = dev_get_platdata(dev);
42  	struct altera_pio_regs *const regs = plat->regs;
43  
44  	if (val)
45  		setbits_le32(&regs->data, 1 << pin);
46  	else
47  		clrbits_le32(&regs->data, 1 << pin);
48  	/* change the data first, then the direction. to avoid glitch */
49  	setbits_le32(&regs->direction, 1 << pin);
50  
51  	return 0;
52  }
53  
54  static int altera_pio_get_value(struct udevice *dev, unsigned pin)
55  {
56  	struct altera_pio_platdata *plat = dev_get_platdata(dev);
57  	struct altera_pio_regs *const regs = plat->regs;
58  
59  	return readl(&regs->data) & (1 << pin);
60  }
61  
62  
63  static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val)
64  {
65  	struct altera_pio_platdata *plat = dev_get_platdata(dev);
66  	struct altera_pio_regs *const regs = plat->regs;
67  
68  	if (val)
69  		setbits_le32(&regs->data, 1 << pin);
70  	else
71  		clrbits_le32(&regs->data, 1 << pin);
72  
73  	return 0;
74  }
75  
76  static int altera_pio_probe(struct udevice *dev)
77  {
78  	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
79  	struct altera_pio_platdata *plat = dev_get_platdata(dev);
80  
81  	uc_priv->gpio_count = plat->gpio_count;
82  	uc_priv->bank_name = plat->bank_name;
83  
84  	return 0;
85  }
86  
87  static int altera_pio_ofdata_to_platdata(struct udevice *dev)
88  {
89  	struct altera_pio_platdata *plat = dev_get_platdata(dev);
90  
91  	plat->regs = map_physmem(devfdt_get_addr(dev),
92  				 sizeof(struct altera_pio_regs),
93  				 MAP_NOCACHE);
94  	plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
95  		"altr,gpio-bank-width", 32);
96  	plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
97  		"gpio-bank-name", NULL);
98  
99  	return 0;
100  }
101  
102  static const struct dm_gpio_ops altera_pio_ops = {
103  	.direction_input	= altera_pio_direction_input,
104  	.direction_output	= altera_pio_direction_output,
105  	.get_value		= altera_pio_get_value,
106  	.set_value		= altera_pio_set_value,
107  };
108  
109  static const struct udevice_id altera_pio_ids[] = {
110  	{ .compatible = "altr,pio-1.0" },
111  	{ }
112  };
113  
114  U_BOOT_DRIVER(altera_pio) = {
115  	.name		= "altera_pio",
116  	.id		= UCLASS_GPIO,
117  	.of_match	= altera_pio_ids,
118  	.ops		= &altera_pio_ops,
119  	.ofdata_to_platdata = altera_pio_ofdata_to_platdata,
120  	.platdata_auto_alloc_size = sizeof(struct altera_pio_platdata),
121  	.probe		= altera_pio_probe,
122  };
123