diff mbox

[U-Boot,v3] nios2 : convert altera_pio to driver model

Message ID 1443258451-25078-1-git-send-email-thomas@wytron.com.tw
State Accepted, archived
Delegated to: Thomas Chou
Headers show

Commit Message

Thomas Chou Sept. 26, 2015, 9:07 a.m. UTC
Convert altera_pio to driver model.

Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
v2
  fix ranges of pio in dts
  fix coding style as Marek suggested.

v3
  change gpio_count device tree binding.

 arch/nios2/dts/3c120_devboard.dts          |  41 ++++
 arch/nios2/include/asm/gpio.h              |  80 +-------
 board/altera/nios2-generic/nios2-generic.c |   7 -
 configs/nios2-generic_defconfig            |   2 +
 drivers/gpio/Kconfig                       |   7 +
 drivers/gpio/altera_pio.c                  | 316 +++++++----------------------
 include/configs/nios2-generic.h            |  20 --
 7 files changed, 127 insertions(+), 346 deletions(-)

Comments

Chin Liang See Sept. 30, 2015, 1:18 a.m. UTC | #1
Hi Thomas,

On Sat, 2015-09-26 at 17:07 +0800, thomas@wytron.com.tw wrote:
> Convert altera_pio to driver model.
> 
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> ---
> v2
>   fix ranges of pio in dts
>   fix coding style as Marek suggested.
> 
> v3
>   change gpio_count device tree binding.
> 
>  arch/nios2/dts/3c120_devboard.dts          |  41 ++++
>  arch/nios2/include/asm/gpio.h              |  80 +-------
>  board/altera/nios2-generic/nios2-generic.c |   7 -
>  configs/nios2-generic_defconfig            |   2 +
>  drivers/gpio/Kconfig                       |   7 +
>  drivers/gpio/altera_pio.c                  | 316 +++++++----------------------
>  include/configs/nios2-generic.h            |  20 --
>  7 files changed, 127 insertions(+), 346 deletions(-)
> 

Acked-by: Chin Liang See <clsee@altera.com>

Thanks
Chin Liang
Simon Glass Sept. 30, 2015, 6:29 p.m. UTC | #2
On 26 September 2015 at 03:07, Thomas Chou <thomas@wytron.com.tw> wrote:
> Convert altera_pio to driver model.
>
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> ---
> v2
>   fix ranges of pio in dts
>   fix coding style as Marek suggested.
>
> v3
>   change gpio_count device tree binding.
>
>  arch/nios2/dts/3c120_devboard.dts          |  41 ++++
>  arch/nios2/include/asm/gpio.h              |  80 +-------
>  board/altera/nios2-generic/nios2-generic.c |   7 -
>  configs/nios2-generic_defconfig            |   2 +
>  drivers/gpio/Kconfig                       |   7 +
>  drivers/gpio/altera_pio.c                  | 316 +++++++----------------------
>  include/configs/nios2-generic.h            |  20 --
>  7 files changed, 127 insertions(+), 346 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

See question below.

[snip]

> -int gpio_direction_output(unsigned gpio, int value)
> +static int altera_pio_ofdata_to_platdata(struct udevice *dev)
>  {
> -       u32 mask;
> -       struct altera_pio *pio;
> +       struct altera_pio_platdata *plat = dev_get_platdata(dev);
>
> -       pio = altera_pio_get_and_mask(gpio, &mask);
> -       if (!pio)
> -               return -1;
> -       if (pio->iot == 'i')
> -               return -1;
> +       plat->regs = ioremap(dev_get_addr(dev),
> +               sizeof(struct altera_pio_regs));

Do we need the ioremap() or can we rely on the 'ranges' handling?

[snip]
Thomas Chou Oct. 1, 2015, 12:38 a.m. UTC | #3
Hi Simon,

On 10/01/2015 02:29 AM, Simon Glass wrote:
> Do we need the ioremap() or can we rely on the 'ranges' handling?

Yes, we do need ioremap() at least for mips, nios2 and alike. For these 
archs, the virtual address that CPU sees is not the same as physical 
address on bus. The virtual address space of these CPus are divided to 
cached kernel space, uncached kernel space, and managed user space. For 
main memory, we would use cached kernel space to run u-boot. While for 
peripheral access, we would use uncached kernel space. The device tree 
describes hardware, and the reg address have to be physical address. We 
need to map the reg address to uncached kernel virtual address. This is 
what ioremap() for. It is not related to ranges translation. Though we 
do need the range translation patch from Stefan as there might be 
bridges between the buses.

Thanks a lot for your review.

Best regards,
Thomas Chou
diff mbox

Patch

diff --git a/arch/nios2/dts/3c120_devboard.dts b/arch/nios2/dts/3c120_devboard.dts
index a35f5fe..781a652 100644
--- a/arch/nios2/dts/3c120_devboard.dts
+++ b/arch/nios2/dts/3c120_devboard.dts
@@ -68,6 +68,9 @@ 
 				<0x00004400 0x08004400 0x00000040>,
 				<0x00004800 0x08004800 0x00000040>,
 				<0x00004c80 0x08004c80 0x00000020>,
+				<0x00004cc0 0x08004cc0 0x00000010>,
+				<0x00004ce0 0x08004ce0 0x00000010>,
+				<0x00004d00 0x08004d00 0x00000010>,
 				<0x00004d50 0x08004d50 0x00000008>,
 				<0x00008000 0x08008000 0x00000020>,
 				<0x00400000 0x08400000 0x00000020>;
@@ -132,6 +135,44 @@ 
 				clock-frequency = <62500000>;
 				u-boot,dm-pre-reloc;
 			};
+
+			user_led_pio_8out: gpio@0x4cc0 {
+				compatible = "altr,pio-1.0";
+				reg = <0x00004cc0 0x00000010>;
+				resetvalue = <255>;
+				altr,gpio-bank-width = <8>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				gpio-bank-name = "led";
+			};
+
+			user_dipsw_pio_8in: gpio@0x4ce0 {
+				compatible = "altr,pio-1.0";
+				reg = <0x00004ce0 0x00000010>;
+				interrupt-parent = <&cpu>;
+				interrupts = <8>;
+				edge_type = <2>;
+				level_trigger = <0>;
+				resetvalue = <0>;
+				altr,gpio-bank-width = <8>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				gpio-bank-name = "dipsw";
+			};
+
+			user_pb_pio_4in: gpio@0x4d00 {
+				compatible = "altr,pio-1.0";
+				reg = <0x00004d00 0x00000010>;
+				interrupt-parent = <&cpu>;
+				interrupts = <9>;
+				edge_type = <2>;
+				level_trigger = <0>;
+				resetvalue = <0>;
+				altr,gpio-bank-width = <4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				gpio-bank-name = "pb";
+			};
 		};
 
 		cfi_flash_64m: flash@0x0 {
diff --git a/arch/nios2/include/asm/gpio.h b/arch/nios2/include/asm/gpio.h
index 908381f..306ab4c 100644
--- a/arch/nios2/include/asm/gpio.h
+++ b/arch/nios2/include/asm/gpio.h
@@ -1,79 +1 @@ 
-/*
- * nios2 gpio driver
- *
- * This gpio core is described in http://nioswiki.com/GPIO
- * bit[0] data
- * bit[1] output enable
- *
- * When CONFIG_SYS_GPIO_BASE is not defined, the board may either
- * provide its own driver or the altera_pio driver may be used.
- *
- * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_NIOS2_GPIO_H_
-#define _ASM_NIOS2_GPIO_H_
-
-#ifdef CONFIG_SYS_GPIO_BASE
-#include <asm/io.h>
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-	return 0;
-}
-
-static inline int gpio_free(unsigned gpio)
-{
-	return 0;
-}
-
-static inline int gpio_direction_input(unsigned gpio)
-{
-	writel(1, CONFIG_SYS_GPIO_BASE + (gpio << 2));
-	return 0;
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-	writel(value ? 3 : 2, CONFIG_SYS_GPIO_BASE + (gpio << 2));
-	return 0;
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-	return readl(CONFIG_SYS_GPIO_BASE + (gpio << 2));
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-	writel(value ? 3 : 2, CONFIG_SYS_GPIO_BASE + (gpio << 2));
-}
-
-static inline int gpio_is_valid(int number)
-{
-	return ((unsigned)number) < CONFIG_SYS_GPIO_WIDTH;
-}
-#else
-#ifdef CONFIG_ALTERA_PIO
-extern int altera_pio_init(u32 base, u8 width, char iot,
-			   u32 rstval, u32 negmask,
-			   const char *label);
-
-extern void altera_pio_info(void);
-#define gpio_status() altera_pio_info()
-#endif
-
-extern int gpio_request(unsigned gpio, const char *label);
-extern int gpio_free(unsigned gpio);
-extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio, int value);
-extern int gpio_get_value(unsigned gpio);
-extern void gpio_set_value(unsigned gpio, int value);
-extern int gpio_is_valid(int number);
-#endif /* CONFIG_SYS_GPIO_BASE */
-
-#endif /* _ASM_NIOS2_GPIO_H_ */
+#include <asm-generic/gpio.h>
diff --git a/board/altera/nios2-generic/nios2-generic.c b/board/altera/nios2-generic/nios2-generic.c
index 384fee9..61d32c7 100644
--- a/board/altera/nios2-generic/nios2-generic.c
+++ b/board/altera/nios2-generic/nios2-generic.c
@@ -37,13 +37,6 @@  int board_early_init_f(void)
 
 int board_early_init_r(void)
 {
-#ifdef CONFIG_ALTERA_PIO
-#ifdef LED_PIO_BASE
-	altera_pio_init(LED_PIO_BASE, LED_PIO_WIDTH, 'o',
-			LED_PIO_RSTVAL, (1 << LED_PIO_WIDTH) - 1,
-			"led");
-#endif
-#endif
 	return 0;
 }
 
diff --git a/configs/nios2-generic_defconfig b/configs/nios2-generic_defconfig
index 9dc6a72..ad72272 100644
--- a/configs/nios2-generic_defconfig
+++ b/configs/nios2-generic_defconfig
@@ -1,5 +1,6 @@ 
 CONFIG_NIOS2=y
 CONFIG_DM_SERIAL=y
+CONFIG_DM_GPIO=y
 CONFIG_TARGET_NIOS2_GENERIC=y
 CONFIG_DEFAULT_DEVICE_TREE="3c120_devboard"
 CONFIG_HUSH_PARSER=y
@@ -15,5 +16,6 @@  CONFIG_CMD_PING=y
 CONFIG_OF_CONTROL=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM=y
+CONFIG_ALTERA_PIO=y
 CONFIG_ALTERA_JTAG_UART=y
 CONFIG_ALTERA_JTAG_UART_BYPASS=y
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ef57a89..9e49471 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -14,6 +14,13 @@  config DM_GPIO
 	  particular GPIOs that they provide. The uclass interface
 	  is defined in include/asm-generic/gpio.h.
 
+config ALTERA_PIO
+	bool "Altera PIO driver"
+	depends on DM_GPIO
+	help
+	  Select this to enable PIO for Altera devices. Please find
+	  details on the "Embedded Peripherals IP User Guide" of Altera.
+
 config DWAPB_GPIO
 	bool "DWAPB GPIO driver"
 	depends on DM && DM_GPIO
diff --git a/drivers/gpio/altera_pio.c b/drivers/gpio/altera_pio.c
index 3ca5907..2590017 100644
--- a/drivers/gpio/altera_pio.c
+++ b/drivers/gpio/altera_pio.c
@@ -1,286 +1,122 @@ 
 /*
- * Driver for Altera's PIO ip core
- *
+ * Copyright (C) 2015  Thomas Chou <thomas@wytron.com.tw>
  * Copyright (C) 2011  Missing Link Electronics
  *                     Joachim Foerster <joachim@missinglinkelectronics.com>
  *
  * SPDX-License-Identifier:	GPL-2.0+
- *
- * To use this driver, in your board's config. header:
- * #define CONFIG_ALTERA_PIO
- * #define CONFIG_SYS_ALTERA_PIO_NUM <number-of-pio-cores>
- * #define CONFIG_SYS_ALTERA_PIO_GPIO_NUM <total-number-of-gpios>
- * And in your board's early setup routine:
- * altera_pio_init(<baseaddr>, <width>, 'i'|'o'|'t',
- *                 <reset-value>, <neg-mask>, "label");
- *  - 'i'|'o'|'t': PIO is input-only/output-only/tri-state
- *  - <reset-value>: for correct initial status display, output-only
- *  - <neg-mask> is meant to be used to in cases of active-low
- *    GPIOs, such as LEDs and buttons (on/pressed == 0). Each bit
- *    which is 1 in <neg-mask> inverts the corresponding GPIO's value
- *    before set/after get. So: gpio_set_value(gpio, 1) => LED on .
- *
- * Do NOT define CONFIG_SYS_GPIO_BASE !
- *
- * Optionally, in your board's config. header:
- * - To force a GPIO numbering scheme like in Linux ...
- * #define CONFIG_GPIO_DOWNTO_NUMBERING
- * ... starting with 255 (default)
- * #define CONFIG_GPIO_DOWNTO_MAX 255
  */
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fdtdec.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
 
-#ifdef CONFIG_GPIO_DOWNTO_NUMBERING
-#ifndef CONFIG_GPIO_DOWNTO_MAX
-#define CONFIG_GPIO_DOWNTO_MAX 255
-#endif
-#endif
-
-#define ALTERA_PIO_DATA		0x0
-#define ALTERA_PIO_DIR		0x4
-
-#define GPIO_LABEL_SIZE		9
+DECLARE_GLOBAL_DATA_PTR;
 
+struct altera_pio_regs {
+	u32	data;			/* Data register */
+	u32	direction;		/* Direction register */
+};
 
-static struct altera_pio {
-	u32 base;
-	u8 width;
-	char iot;
-	u32 negmask;
-	u32 sh_data;
-	u32 sh_dir;
-	int gidx;
-	char label[GPIO_LABEL_SIZE];
-} pios[CONFIG_SYS_ALTERA_PIO_NUM];
+struct altera_pio_platdata {
+	struct altera_pio_regs *regs;
+	int gpio_count;
+	const char *bank_name;
+};
 
-static int pio_num;
-
-static struct altera_pio_gpio {
-	unsigned num;
-	struct altera_pio *pio;
-	char reqlabel[GPIO_LABEL_SIZE];
-} gpios[CONFIG_SYS_ALTERA_PIO_GPIO_NUM];
-
-static int pio_gpio_num;
-
-
-static int altera_pio_gidx(unsigned gpio)
+static int altera_pio_direction_input(struct udevice *dev, unsigned pin)
 {
-	int i;
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-	for (i = 0; i < pio_gpio_num; ++i) {
-		if (gpio == gpios[i].num)
-			break;
-	}
-	if (i >= pio_gpio_num)
-		return -1;
-	return i;
-}
+	clrbits_le32(&regs->direction, 1 << pin);
 
-static struct altera_pio *altera_pio_get_and_mask(unsigned gpio, u32 *mask)
-{
-	int gidx = altera_pio_gidx(gpio);
-	if (gidx < 0)
-		return NULL;
-	if (mask)
-		*mask = 1 << (gidx - gpios[gidx].pio->gidx);
-	return gpios[gidx].pio;
+	return 0;
 }
 
-#define altera_pio_use_gidx(_gidx, _reqlabel) \
-	{ strncpy(gpios[_gidx].reqlabel, _reqlabel, GPIO_LABEL_SIZE); }
-#define altera_pio_unuse_gidx(_gidx) { gpios[_gidx].reqlabel[0] = '\0'; }
-#define altera_pio_is_gidx_used(_gidx) (gpios[_gidx].reqlabel[0] != '\0')
-
-static int altera_pio_gpio_init(struct altera_pio *pio, u8 width)
+static int altera_pio_direction_output(struct udevice *dev, unsigned pin,
+				     int val)
 {
-	u8 gidx = pio_gpio_num;
-	int i;
-
-	if (!width)
-		return -1;
-	if ((pio_gpio_num + width) > CONFIG_SYS_ALTERA_PIO_GPIO_NUM)
-		return -1;
-
-	for (i = 0; i < width; ++i) {
-#ifdef CONFIG_GPIO_DOWNTO_NUMBERING
-		gpios[pio_gpio_num + i].num = \
-			CONFIG_GPIO_DOWNTO_MAX + 1 - gidx - width + i;
-#else
-		gpios[pio_gpio_num + i].num = pio_gpio_num + i;
-#endif
-		gpios[pio_gpio_num + i].pio = pio;
-		altera_pio_unuse_gidx(pio_gpio_num + i);
-	}
-	pio_gpio_num += width;
-	return gidx;
-}
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-int altera_pio_init(u32 base, u8 width, char iot, u32 rstval, u32 negmask,
-		 const char *label)
-{
-	if (pio_num >= CONFIG_SYS_ALTERA_PIO_NUM)
-		return -1;
+	if (val)
+		setbits_le32(&regs->data, 1 << pin);
+	else
+		clrbits_le32(&regs->data, 1 << pin);
+	/* change the data first, then the direction. to avoid glitch */
+	setbits_le32(&regs->direction, 1 << pin);
 
-	pios[pio_num].base = base;
-	pios[pio_num].width = width;
-	pios[pio_num].iot = iot;
-	switch (iot) {
-	case 'i':
-		/* input only */
-		pios[pio_num].sh_dir = 0;
-		pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
-		break;
-	case 'o':
-		/* output only */
-		pios[pio_num].sh_dir = 0xffffffff & ((1 << width) - 1);
-		pios[pio_num].sh_data = rstval;
-		break;
-	case 't':
-		/* bidir, tri-state */
-		pios[pio_num].sh_dir = readl(base + ALTERA_PIO_DIR);
-		pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
-		break;
-	default:
-		return -1;
-	}
-	pios[pio_num].negmask = negmask & ((1 << width) - 1);
-	pios[pio_num].gidx = altera_pio_gpio_init(&pios[pio_num], width);
-	if (pios[pio_num].gidx < 0)
-		return -1;
-	strncpy(pios[pio_num].label, label, GPIO_LABEL_SIZE);
-	return pio_num++;
+	return 0;
 }
 
-void altera_pio_info(void)
+static int altera_pio_get_value(struct udevice *dev, unsigned pin)
 {
-	int i;
-	int j;
-	int gidx;
-	u32 mask;
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-	for (i = 0; i < pio_num; ++i) {
-		printf("Altera PIO % 2d, @0x%08x, "
-			"width: %u, label: %s\n",
-		       i, pios[i].base, pios[i].width, pios[i].label);
-		gidx = pios[i].gidx;
-		for (j = gidx; j < (gidx + pios[i].width); ++j) {
-			mask = 1 << (j - gidx);
-			printf("\tGPIO % 4d: %s %s [%c] %s\n",
-				gpios[j].num,
-				gpios[j].pio->sh_dir & mask ? "out" : " in",
-				gpio_get_value(gpios[j].num) ? "set" : "clr",
-				altera_pio_is_gidx_used(j) ? 'x' : ' ',
-				gpios[j].reqlabel);
-		}
-	}
+	return readl(&regs->data) & (1 << pin);
 }
 
 
-int gpio_request(unsigned gpio, const char *label)
+static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val)
 {
-	int gidx = altera_pio_gidx(gpio);
-	if (gidx < 0)
-		return gidx;
-	if (altera_pio_is_gidx_used(gidx))
-		return -1;
-
-	altera_pio_use_gidx(gidx, label);
-	return 0;
-}
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-int gpio_free(unsigned gpio)
-{
-	int gidx = altera_pio_gidx(gpio);
-	if (gidx < 0)
-		return gidx;
-	if (!altera_pio_is_gidx_used(gidx))
-		return -1;
+	if (val)
+		setbits_le32(&regs->data, 1 << pin);
+	else
+		clrbits_le32(&regs->data, 1 << pin);
 
-	altera_pio_unuse_gidx(gidx);
 	return 0;
 }
 
-int gpio_direction_input(unsigned gpio)
+static int altera_pio_probe(struct udevice *dev)
 {
-	u32 mask;
-	struct altera_pio *pio;
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
 
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return -1;
-	if (pio->iot == 'o')
-		return -1;
+	uc_priv->gpio_count = plat->gpio_count;
+	uc_priv->bank_name = plat->bank_name;
 
-	writel(pio->sh_dir &= ~mask, pio->base + ALTERA_PIO_DIR);
 	return 0;
 }
 
-int gpio_direction_output(unsigned gpio, int value)
+static int altera_pio_ofdata_to_platdata(struct udevice *dev)
 {
-	u32 mask;
-	struct altera_pio *pio;
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
 
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return -1;
-	if (pio->iot == 'i')
-		return -1;
+	plat->regs = ioremap(dev_get_addr(dev),
+		sizeof(struct altera_pio_regs));
+	plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+		"altr,gpio-bank-width", 0);
+	plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset,
+		"gpio-bank-name", NULL);
 
-	value = (pio->negmask & mask) ? !value : value;
-	if (value)
-		pio->sh_data |= mask;
-	else
-		pio->sh_data &= ~mask;
-	writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
-	writel(pio->sh_dir |= mask, pio->base + ALTERA_PIO_DIR);
 	return 0;
 }
 
-int gpio_get_value(unsigned gpio)
-{
-	u32 mask;
-	struct altera_pio *pio;
-	u32 val;
-
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return -1;
-
-	if ((pio->sh_dir & mask) || (pio->iot == 'o'))
-		val = pio->sh_data & mask;
-	else
-		val = readl(pio->base + ALTERA_PIO_DATA) & mask;
-	return (pio->negmask & mask) ? !val : val;
-}
-
-void gpio_set_value(unsigned gpio, int value)
-{
-	u32 mask;
-	struct altera_pio *pio;
-
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return;
-	if (pio->iot == 'i')
-		return;
-
-	value = (pio->negmask & mask) ? !value : value;
-	if (value)
-		pio->sh_data |= mask;
-	else
-		pio->sh_data &= ~mask;
-	writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
-	return;
-}
-
-int gpio_is_valid(int number)
-{
-	int gidx = altera_pio_gidx(number);
-
-	if (gidx < 0)
-		return 1;
-	return 0;
-}
+static const struct dm_gpio_ops altera_pio_ops = {
+	.direction_input	= altera_pio_direction_input,
+	.direction_output	= altera_pio_direction_output,
+	.get_value		= altera_pio_get_value,
+	.set_value		= altera_pio_set_value,
+};
+
+static const struct udevice_id altera_pio_ids[] = {
+	{ .compatible = "altr,pio-1.0" },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_pio) = {
+	.name		= "altera_pio",
+	.id		= UCLASS_GPIO,
+	.of_match	= altera_pio_ids,
+	.ops		= &altera_pio_ops,
+	.ofdata_to_platdata = altera_pio_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct altera_pio_platdata),
+	.probe		= altera_pio_probe,
+};
diff --git a/include/configs/nios2-generic.h b/include/configs/nios2-generic.h
index dcb90de..90ccbd1 100644
--- a/include/configs/nios2-generic.h
+++ b/include/configs/nios2-generic.h
@@ -33,26 +33,6 @@ 
 #define CONFIG_SYS_TIMER_RATE		CONFIG_SYS_TIMER_FREQ
 
 /*
- * STATUS LED
- */
-#define CONFIG_ALTERA_PIO
-#define CONFIG_SYS_ALTERA_PIO_NUM	1
-#define CONFIG_SYS_ALTERA_PIO_GPIO_NUM	LED_PIO_WIDTH
-
-#define CONFIG_STATUS_LED		/* Enable status driver */
-#define CONFIG_BOARD_SPECIFIC_LED
-#define CONFIG_GPIO_LED		/* Enable GPIO LED driver */
-#define CONFIG_GPIO			/* Enable GPIO driver */
-#define LED_PIO_BASE			USER_LED_PIO_8OUT_BASE
-#define LED_PIO_WIDTH			8
-#define LED_PIO_RSTVAL			0xff
-
-#define STATUS_LED_BIT			0	/* Bit-0 on GPIO */
-#define STATUS_LED_STATE		STATUS_LED_ON
-#define STATUS_LED_PERIOD	(CONFIG_SYS_HZ / 2)	/* 500 msec */
-#define STATUS_LED_BOOT			STATUS_LED_BIT
-
-/*
  * BOOTP options
  */
 #define CONFIG_BOOTP_BOOTFILESIZE