ixp4xx/fsg3: Added LEDs support, and refreshed patches for 2.6.23.12
[openwrt/svn-archive/archive.git] / target / linux / ixp4xx / patches-2.6.23 / 013-fsg3_support.patch
index b08325f7c95ea8a6bf0124dd7a3123bf4a530534..919571a0b4a124f47afa45b7fad283bae414d47a 100644 (file)
@@ -1,6 +1,7 @@
-diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-pci.c linux-2.6.23/arch/arm/mach-ixp4xx/fsg-pci.c
---- linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-pci.c   1969-12-31 18:00:00.000000000 -0600
-+++ linux-2.6.23/arch/arm/mach-ixp4xx/fsg-pci.c        2007-10-11 00:55:34.000000000 -0500
+Index: linux-2.6.23.12/arch/arm/mach-ixp4xx/fsg-pci.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.12/arch/arm/mach-ixp4xx/fsg-pci.c     2008-01-05 13:32:23.000000000 +1030
 @@ -0,0 +1,71 @@
 +/*
 + * arch/arch/mach-ixp4xx/fsg-pci.c
@@ -73,10 +74,11 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-pci.c linux-2.6.23/arch/ar
 +}
 +
 +subsys_initcall(fsg_pci_init);
-diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c linux-2.6.23/arch/arm/mach-ixp4xx/fsg-setup.c
---- linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c 1969-12-31 18:00:00.000000000 -0600
-+++ linux-2.6.23/arch/arm/mach-ixp4xx/fsg-setup.c      2007-10-11 00:55:34.000000000 -0500
-@@ -0,0 +1,186 @@
+Index: linux-2.6.23.12/arch/arm/mach-ixp4xx/fsg-setup.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.12/arch/arm/mach-ixp4xx/fsg-setup.c   2008-01-05 14:07:41.000000000 +1030
+@@ -0,0 +1,148 @@
 +/*
 + * arch/arm/mach-ixp4xx/fsg-setup.c
 + *
@@ -94,7 +96,8 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c linux-2.6.23/arch/
 +#include <linux/serial.h>
 +#include <linux/serial_8250.h>
 +#include <linux/leds.h>
-+#include <linux/i2c-gpio.h>
++#include <linux/mtd/mtd.h>
++#include <linux/reboot.h>
 +
 +#include <asm/mach-types.h>
 +#include <asm/mach/arch.h>
@@ -117,67 +120,18 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c linux-2.6.23/arch/
 +      .resource               = &fsg_flash_resource,
 +};
 +
-+static struct i2c_gpio_platform_data fsg_i2c_gpio_data = {
++static struct ixp4xx_i2c_pins fsg_i2c_gpio_pins = {
 +      .sda_pin                = FSG_SDA_PIN,
 +      .scl_pin                = FSG_SCL_PIN,
 +};
 +
-+static struct platform_device fsg_i2c_gpio = {
-+      .name                   = "i2c-gpio",
-+      .id                     = 0,
-+      .dev     = {
-+              .platform_data  = &fsg_i2c_gpio_data,
-+      },
++static struct platform_device fsg_i2c_controller = {
++        .name                   = "IXP4XX-I2C",
++        .id                     = 0,
++        .dev.platform_data      = &fsg_i2c_gpio_pins,
++        .num_resources          = 0,
 +};
 +
-+#ifdef CONFIG_LEDS_CLASS
-+static struct resource fsg_led_resources[] = {
-+      {
-+              .name           = "ring",
-+              .start          = FSG_LED_RING_GPIO,
-+              .end            = FSG_LED_RING_GPIO,
-+              .flags          = IXP4XX_GPIO_HIGH,
-+      },
-+      {
-+              .name           = "sync",
-+              .start          = FSG_LED_SYNC_GPIO,
-+              .end            = FSG_LED_SYNC_GPIO,
-+              .flags          = IXP4XX_GPIO_HIGH,
-+      },
-+      {
-+              .name           = "usb",
-+              .start          = FSG_LED_USB_GPIO,
-+              .end            = FSG_LED_USB_GPIO,
-+              .flags          = IXP4XX_GPIO_HIGH,
-+      },
-+      {
-+              .name           = "sata",
-+              .start          = FSG_LED_SATA_GPIO,
-+              .end            = FSG_LED_SATA_GPIO,
-+              .flags          = IXP4XX_GPIO_HIGH,
-+      },
-+      {
-+              .name           = "wan",
-+              .start          = FSG_LED_WAN_GPIO,
-+              .end            = FSG_LED_WAN_GPIO,
-+              .flags          = IXP4XX_GPIO_HIGH,
-+      },
-+      {
-+              .name           = "wlan",
-+              .start          = FSG_LED_WLAN_GPIO,
-+              .end            = FSG_LED_WLAN_GPIO,
-+              .flags          = IXP4XX_GPIO_HIGH,
-+      },
-+};
-+
-+static struct platform_device fsg_leds = {
-+        .name                   = "IXP4XX-GPIO-LED",
-+        .id                     = -1,
-+        .num_resources          = ARRAY_SIZE(fsg_led_resources),
-+        .resource               = fsg_led_resources,
-+};
-+#endif
-+
 +static struct resource fsg_uart_resources[] = {
 +      {
 +              .start          = IXP4XX_UART1_BASE_PHYS,
@@ -221,14 +175,23 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c linux-2.6.23/arch/
 +      .resource               = fsg_uart_resources,
 +};
 +
++static struct platform_device fsg_leds = {
++      .name           = "fsg-led",
++      .id             = -1,
++};
++
 +static struct platform_device *fsg_devices[] __initdata = {
-+      &fsg_i2c_gpio,
++      &fsg_i2c_controller,
 +      &fsg_flash,
-+#ifdef CONFIG_LEDS_IXP4XX
 +      &fsg_leds,
-+#endif
 +};
 +
++static void fsg_power_off(void)
++{
++      printk("Restarting system.\n");
++      machine_restart(NULL);
++}
++
 +static void __init fsg_init(void)
 +{
 +      ixp4xx_sys_init();
@@ -237,8 +200,10 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c linux-2.6.23/arch/
 +      fsg_flash_resource.end =
 +              IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
 +
-+        *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
-+        *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
++      pm_power_off = fsg_power_off;
++
++      *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
++      *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
 +
 +      /* Configure CS2 for operation, 8bit and writable */
 +      *IXP4XX_EXP_CS2 = 0xbfff0002;
@@ -253,7 +218,6 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c linux-2.6.23/arch/
 +}
 +
 +MACHINE_START(FSG, "Freecom FSG-3")
-+      /* Maintainer: www.nslu2-linux.org */
 +      .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
 +      .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 +      .map_io         = ixp4xx_map_io,
@@ -263,10 +227,11 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/fsg-setup.c linux-2.6.23/arch/
 +      .init_machine   = fsg_init,
 +MACHINE_END
 +
-diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/Kconfig linux-2.6.23/arch/arm/mach-ixp4xx/Kconfig
---- linux-2.6.23.orig/arch/arm/mach-ixp4xx/Kconfig     2007-10-09 15:31:38.000000000 -0500
-+++ linux-2.6.23/arch/arm/mach-ixp4xx/Kconfig  2007-10-11 00:55:34.000000000 -0500
-@@ -125,6 +125,15 @@ config    ARCH_IXDP4XX
+Index: linux-2.6.23.12/arch/arm/mach-ixp4xx/Kconfig
+===================================================================
+--- linux-2.6.23.12.orig/arch/arm/mach-ixp4xx/Kconfig  2008-01-05 13:29:20.000000000 +1030
++++ linux-2.6.23.12/arch/arm/mach-ixp4xx/Kconfig       2008-01-05 14:07:40.000000000 +1030
+@@ -125,6 +125,15 @@
        depends on ARCH_IXDP425 || MACH_IXDP465 || MACH_KIXRP435
        default y
  
@@ -282,10 +247,11 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/Kconfig linux-2.6.23/arch/arm/
  #
  # Certain registers and IRQs are only enabled if supporting IXP465 CPUs
  #
-diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/Makefile linux-2.6.23/arch/arm/mach-ixp4xx/Makefile
---- linux-2.6.23.orig/arch/arm/mach-ixp4xx/Makefile    2007-10-09 15:31:38.000000000 -0500
-+++ linux-2.6.23/arch/arm/mach-ixp4xx/Makefile 2007-10-11 00:55:34.000000000 -0500
-@@ -15,6 +15,7 @@ obj-pci-$(CONFIG_MACH_NAS100D)               += nas10
+Index: linux-2.6.23.12/arch/arm/mach-ixp4xx/Makefile
+===================================================================
+--- linux-2.6.23.12.orig/arch/arm/mach-ixp4xx/Makefile 2008-01-05 13:29:20.000000000 +1030
++++ linux-2.6.23.12/arch/arm/mach-ixp4xx/Makefile      2008-01-05 14:07:40.000000000 +1030
+@@ -15,6 +15,7 @@
  obj-pci-$(CONFIG_MACH_DSMG600)                += dsmg600-pci.o
  obj-pci-$(CONFIG_MACH_GATEWAY7001)    += gateway7001-pci.o
  obj-pci-$(CONFIG_MACH_WG302V2)                += wg302v2-pci.o
@@ -293,17 +259,18 @@ diff -uprN linux-2.6.23.orig/arch/arm/mach-ixp4xx/Makefile linux-2.6.23/arch/arm
  
  obj-y += common.o
  
-@@ -28,5 +29,6 @@ obj-$(CONFIG_MACH_NAS100D)   += nas100d-se
+@@ -28,5 +29,6 @@
  obj-$(CONFIG_MACH_DSMG600)      += dsmg600-setup.o dsmg600-power.o
  obj-$(CONFIG_MACH_GATEWAY7001)        += gateway7001-setup.o
  obj-$(CONFIG_MACH_WG302V2)    += wg302v2-setup.o
-+obj-$(CONFIG_MACH_FSG)                += fsg-setup.o
++obj-$(CONFIG_MACH_FSG)                += fsg-setup.o fsg-power.o
  
  obj-$(CONFIG_PCI)             += $(obj-pci-$(CONFIG_PCI)) common-pci.o
-diff -uprN linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/fsg.h linux-2.6.23/include/asm-arm/arch-ixp4xx/fsg.h
---- linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/fsg.h        1969-12-31 18:00:00.000000000 -0600
-+++ linux-2.6.23/include/asm-arm/arch-ixp4xx/fsg.h     2007-10-11 00:55:34.000000000 -0500
-@@ -0,0 +1,74 @@
+Index: linux-2.6.23.12/include/asm-arm/arch-ixp4xx/fsg.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.12/include/asm-arm/arch-ixp4xx/fsg.h  2008-01-05 14:08:23.000000000 +1030
+@@ -0,0 +1,58 @@
 +/*
 + * include/asm-arm/arch-ixp4xx/fsg.h
 + *
@@ -356,31 +323,16 @@ diff -uprN linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/fsg.h linux-2.6.23/incl
 +
 +/* LEDs */
 +
-+#define FSG_LED_RING_GPIO     0
-+#define FSG_LED_SYNC_GPIO     1
-+#define FSG_LED_USB_GPIO      2
-+#define FSG_LED_SATA_GPIO     3
-+#define FSG_LED_WAN_GPIO      4
-+#define FSG_LED_WLAN_GPIO     5
-+
-+/* %%% REMOVE %%%
-+#define FSG_PCI_SLOT0_PIN     6
-+#define FSG_PCI_SLOT1_PIN     7
-+
-+#define       FSG_PCI_SLOT0_DEVID     14
-+#define       FSG_PCI_SLOT1_DEVID     15
-+
-+#define       FSG_IDE_BASE_PHYS       IXP4XX_EXP_BUS_BASE(3)
-+#define       FSG_IDE_BASE_VIRT       0xFFFE1000
-+#define       FSG_IDE_REGION_SIZE     0x1000
-+
-+#define       FSG_IDE_DATA_PORT       0xFFFE10E0
-+#define       FSG_IDE_CTRL_PORT       0xFFFE10FC
-+#define       FSG_IDE_ERROR_PORT      0xFFFE10E2
-+*/
-diff -uprN linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/hardware.h linux-2.6.23/include/asm-arm/arch-ixp4xx/hardware.h
---- linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/hardware.h   2007-10-09 15:31:38.000000000 -0500
-+++ linux-2.6.23/include/asm-arm/arch-ixp4xx/hardware.h        2007-10-11 00:55:34.000000000 -0500
++#define FSG_LED_WLAN_BIT      0
++#define FSG_LED_WAN_BIT               1
++#define FSG_LED_SATA_BIT      2
++#define FSG_LED_USB_BIT               4
++#define FSG_LED_RING_BIT      5
++#define FSG_LED_SYNC_BIT      7
+Index: linux-2.6.23.12/include/asm-arm/arch-ixp4xx/hardware.h
+===================================================================
+--- linux-2.6.23.12.orig/include/asm-arm/arch-ixp4xx/hardware.h        2008-01-05 13:29:20.000000000 +1030
++++ linux-2.6.23.12/include/asm-arm/arch-ixp4xx/hardware.h     2008-01-05 14:07:39.000000000 +1030
 @@ -45,5 +45,6 @@
  #include "nslu2.h"
  #include "nas100d.h"
@@ -388,9 +340,10 @@ diff -uprN linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/hardware.h linux-2.6.23
 +#include "fsg.h"
  
  #endif  /* _ASM_ARCH_HARDWARE_H */
-diff -uprN linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/irqs.h linux-2.6.23/include/asm-arm/arch-ixp4xx/irqs.h
---- linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/irqs.h       2007-10-09 15:31:38.000000000 -0500
-+++ linux-2.6.23/include/asm-arm/arch-ixp4xx/irqs.h    2007-10-11 00:55:34.000000000 -0500
+Index: linux-2.6.23.12/include/asm-arm/arch-ixp4xx/irqs.h
+===================================================================
+--- linux-2.6.23.12.orig/include/asm-arm/arch-ixp4xx/irqs.h    2008-01-05 13:29:20.000000000 +1030
++++ linux-2.6.23.12/include/asm-arm/arch-ixp4xx/irqs.h 2008-01-05 13:29:24.000000000 +1030
 @@ -128,4 +128,17 @@
  #define        IRQ_DSMG600_PCI_INTE    IRQ_IXP4XX_GPIO7
  #define        IRQ_DSMG600_PCI_INTF    IRQ_IXP4XX_GPIO6
@@ -409,3 +362,372 @@ diff -uprN linux-2.6.23.orig/include/asm-arm/arch-ixp4xx/irqs.h linux-2.6.23/inc
 +*/
 +
  #endif
+Index: linux-2.6.23.12/arch/arm/mach-ixp4xx/fsg-power.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.12/arch/arm/mach-ixp4xx/fsg-power.c   2008-01-05 13:32:27.000000000 +1030
+@@ -0,0 +1,87 @@
++/*
++ * arch/arm/mach-ixp4xx/fsg-power.c
++ *
++ * FSG Power/Reset driver
++ *
++ * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
++ *
++ * based on nslu2-power.c
++ *  Copyright (C) 2005 Tower Technologies
++ *
++ * 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.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/reboot.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++
++#include <asm/mach-types.h>
++
++static irqreturn_t fsg_power_handler(int irq, void *dev_id)
++{
++      /* Signal init to do the ctrlaltdel action, this will bypass init if
++       * it hasn't started and do a kernel_restart.
++       */
++      ctrl_alt_del();
++
++      return IRQ_HANDLED;
++}
++
++static irqreturn_t fsg_reset_handler(int irq, void *dev_id)
++{
++      /* This is the paper-clip reset, it shuts the machine down directly.
++       */
++      machine_power_off();
++
++      return IRQ_HANDLED;
++}
++
++static int __init fsg_power_init(void)
++{
++      if (!(machine_is_fsg()))
++              return 0;
++
++      set_irq_type(FSG_RB_IRQ, IRQT_LOW);
++      set_irq_type(FSG_SB_IRQ, IRQT_LOW);
++
++      if (request_irq(FSG_RB_IRQ, &fsg_reset_handler,
++              IRQF_DISABLED, "FSG reset button", NULL) < 0) {
++
++              printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
++                      FSG_RB_IRQ);
++
++              return -EIO;
++      }
++
++      if (request_irq(FSG_SB_IRQ, &fsg_power_handler,
++              IRQF_DISABLED, "FSG power button", NULL) < 0) {
++
++              printk(KERN_DEBUG "Power Button IRQ %d not available\n",
++                      FSG_SB_IRQ);
++
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static void __exit fsg_power_exit(void)
++{
++      if (!(machine_is_fsg()))
++              return;
++
++      free_irq(FSG_SB_IRQ, NULL);
++      free_irq(FSG_RB_IRQ, NULL);
++}
++
++module_init(fsg_power_init);
++module_exit(fsg_power_exit);
++
++MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
++MODULE_DESCRIPTION("FSG Power/Reset driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.23.12/drivers/leds/Kconfig
+===================================================================
+--- linux-2.6.23.12.orig/drivers/leds/Kconfig  2008-01-05 13:31:05.000000000 +1030
++++ linux-2.6.23.12/drivers/leds/Kconfig       2008-01-05 13:33:48.000000000 +1030
+@@ -48,6 +48,12 @@
+         particular board must have LEDs and they must be connected
+         to the GPIO lines.  If unsure, say Y.
++config LEDS_FSG
++      tristate "LED Support for the Freecom FSG-3"
++      depends on LEDS_CLASS && MACH_FSG
++      help
++        This option enables support for the LEDs on the Freecom FSG-3.
++
+ config LEDS_TOSA
+       tristate "LED Support for the Sharp SL-6000 series"
+       depends on LEDS_CLASS && PXA_SHARPSL
+Index: linux-2.6.23.12/drivers/leds/Makefile
+===================================================================
+--- linux-2.6.23.12.orig/drivers/leds/Makefile 2008-01-05 13:31:04.000000000 +1030
++++ linux-2.6.23.12/drivers/leds/Makefile      2008-01-05 13:33:21.000000000 +1030
+@@ -9,6 +9,7 @@
+ obj-$(CONFIG_LEDS_LOCOMO)             += leds-locomo.o
+ obj-$(CONFIG_LEDS_SPITZ)              += leds-spitz.o
+ obj-$(CONFIG_LEDS_IXP4XX)             += leds-ixp4xx-gpio.o
++obj-$(CONFIG_LEDS_FSG)                        += leds-fsg.o
+ obj-$(CONFIG_LEDS_TOSA)                       += leds-tosa.o
+ obj-$(CONFIG_LEDS_S3C24XX)            += leds-s3c24xx.o
+ obj-$(CONFIG_LEDS_AMS_DELTA)          += leds-ams-delta.o
+Index: linux-2.6.23.12/drivers/leds/leds-fsg.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.12/drivers/leds/leds-fsg.c    2008-01-05 13:31:52.000000000 +1030
+@@ -0,0 +1,243 @@
++/*
++ * LED Driver for the Freecom FSG-3
++ *
++ * Copyright (c) 2008 Rod Whitby <rod@whitby.id.au>
++ *
++ * Author: Rod Whitby <rod@whitby.id.au>
++ *
++ * Based on leds-spitz.c
++ * Copyright 2005-2006 Openedhand Ltd.
++ * Author: Richard Purdie <rpurdie@openedhand.com>
++ *
++ * 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.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/leds.h>
++#include <asm/arch/hardware.h>
++#include <asm/io.h>
++
++static short __iomem *latch_address;
++static unsigned short latch_value;
++
++
++static void fsg_led_wlan_set(struct led_classdev *led_cdev, enum led_brightness value)
++{
++      if (value) {
++              latch_value &= ~(1 << FSG_LED_WLAN_BIT);
++              *latch_address = latch_value;
++      }
++      else {
++              latch_value |=  (1 << FSG_LED_WLAN_BIT);
++              *latch_address = latch_value;
++      }
++}
++
++static void fsg_led_wan_set(struct led_classdev *led_cdev, enum led_brightness value)
++{
++      if (value) {
++              latch_value &= ~(1 << FSG_LED_WAN_BIT);
++              *latch_address = latch_value;
++      }
++      else {
++              latch_value |=  (1 << FSG_LED_WAN_BIT);
++              *latch_address = latch_value;
++      }
++}
++
++static void fsg_led_sata_set(struct led_classdev *led_cdev, enum led_brightness value)
++{
++      if (value) {
++              latch_value &= ~(1 << FSG_LED_SATA_BIT);
++              *latch_address = latch_value;
++      }
++      else {
++              latch_value |=  (1 << FSG_LED_SATA_BIT);
++              *latch_address = latch_value;
++      }
++}
++
++static void fsg_led_usb_set(struct led_classdev *led_cdev, enum led_brightness value)
++{
++      if (value) {
++              latch_value &= ~(1 << FSG_LED_USB_BIT);
++              *latch_address = latch_value;
++      }
++      else {
++              latch_value |=  (1 << FSG_LED_USB_BIT);
++              *latch_address = latch_value;
++      }
++}
++
++static void fsg_led_sync_set(struct led_classdev *led_cdev, enum led_brightness value)
++{
++      if (value) {
++              latch_value &= ~(1 << FSG_LED_SYNC_BIT);
++              *latch_address = latch_value;
++      }
++      else {
++              latch_value |=  (1 << FSG_LED_SYNC_BIT);
++              *latch_address = latch_value;
++      }
++}
++
++static void fsg_led_ring_set(struct led_classdev *led_cdev, enum led_brightness value)
++{
++      if (value) {
++              latch_value &= ~(1 << FSG_LED_RING_BIT);
++              *latch_address = latch_value;
++      }
++      else {
++              latch_value |=  (1 << FSG_LED_RING_BIT);
++              *latch_address = latch_value;
++      }
++}
++
++
++
++static struct led_classdev fsg_wlan_led = {
++      .name                   = "fsg:wlan",
++      .brightness_set         = fsg_led_wlan_set,
++};
++
++static struct led_classdev fsg_wan_led = {
++      .name                   = "fsg:wan",
++      .brightness_set         = fsg_led_wan_set,
++};
++
++static struct led_classdev fsg_sata_led = {
++      .name                   = "fsg:sata",
++      .brightness_set         = fsg_led_sata_set,
++};
++
++static struct led_classdev fsg_usb_led = {
++      .name                   = "fsg:usb",
++      .brightness_set         = fsg_led_usb_set,
++};
++
++static struct led_classdev fsg_sync_led = {
++      .name                   = "fsg:sync",
++      .brightness_set         = fsg_led_sync_set,
++};
++
++static struct led_classdev fsg_ring_led = {
++      .name                   = "fsg:ring",
++      .brightness_set         = fsg_led_ring_set,
++};
++
++
++
++#ifdef CONFIG_PM
++static int fsg_led_suspend(struct platform_device *dev, pm_message_t state)
++{
++      led_classdev_suspend(&fsg_wlan_led);
++      led_classdev_suspend(&fsg_wan_led);
++      led_classdev_suspend(&fsg_sata_led);
++      led_classdev_suspend(&fsg_usb_led);
++      led_classdev_suspend(&fsg_sync_led);
++      led_classdev_suspend(&fsg_ring_led);
++      return 0;
++}
++
++static int fsg_led_resume(struct platform_device *dev)
++{
++      led_classdev_resume(&fsg_wlan_led);
++      led_classdev_resume(&fsg_wan_led);
++      led_classdev_resume(&fsg_sata_led);
++      led_classdev_resume(&fsg_usb_led);
++      led_classdev_resume(&fsg_sync_led);
++      led_classdev_resume(&fsg_ring_led);
++      return 0;
++}
++#endif
++
++
++static int fsg_led_probe(struct platform_device *pdev)
++{
++      int ret;
++
++      /* FIXME: Need to work out how to handle failure below */
++
++      ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
++      if (ret < 0)
++              return ret;
++
++      ret = led_classdev_register(&pdev->dev, &fsg_wan_led);
++      if (ret < 0)
++              return ret;
++
++      ret = led_classdev_register(&pdev->dev, &fsg_sata_led);
++      if (ret < 0)
++              return ret;
++
++      ret = led_classdev_register(&pdev->dev, &fsg_usb_led);
++      if (ret < 0)
++              return ret;
++
++      ret = led_classdev_register(&pdev->dev, &fsg_sync_led);
++      if (ret < 0)
++              return ret;
++
++      ret = led_classdev_register(&pdev->dev, &fsg_ring_led);
++      if (ret < 0)
++              return ret;
++
++      return ret;
++}
++
++static int fsg_led_remove(struct platform_device *pdev)
++{
++      led_classdev_unregister(&fsg_wlan_led);
++      led_classdev_unregister(&fsg_wan_led);
++      led_classdev_unregister(&fsg_sata_led);
++      led_classdev_unregister(&fsg_usb_led);
++      led_classdev_unregister(&fsg_sync_led);
++      led_classdev_unregister(&fsg_ring_led);
++
++      return 0;
++}
++
++
++static struct platform_driver fsg_led_driver = {
++      .probe          = fsg_led_probe,
++      .remove         = fsg_led_remove,
++#ifdef CONFIG_PM
++      .suspend        = fsg_led_suspend,
++      .resume         = fsg_led_resume,
++#endif
++      .driver         = {
++              .name           = "fsg-led",
++      },
++};
++
++
++static int __init fsg_led_init(void)
++{
++      /* Map the LED chip select address space */
++      latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
++      if (!latch_address)
++              return -ENOMEM;
++      latch_value = 0xffff;
++      *latch_address = latch_value;
++      /* FIXME: We leak memory if the next line fails */
++      return platform_driver_register(&fsg_led_driver);
++}
++
++static void __exit fsg_led_exit(void)
++{
++      platform_driver_unregister(&fsg_led_driver);
++      iounmap(latch_address);
++}
++
++
++module_init(fsg_led_init);
++module_exit(fsg_led_exit);
++
++MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
++MODULE_DESCRIPTION("Freecom FSG-3 LED driver");
++MODULE_LICENSE("GPL");