Merge branches 'arm', 'at91', 'bcmring', 'ep93xx', 'mach-types', 'misc' and 'w90x900...
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-ep93xx / core.c
index 204dc5cbd0b88367001cad3ec38855bf8832cd5c..16b92c37ec99a7107ec29ef51103a67ba0c4c191 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
+#include <linux/platform_device.h>
 #include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
 #include <linux/dma-mapping.h>
-#include <linux/time.h>
 #include <linux/timex.h>
-#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 #include <linux/termios.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
-#include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
 #include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
-#include <mach/gpio.h>
 
 #include <asm/hardware/vic.h>
 
@@ -98,7 +82,7 @@ void __init ep93xx_map_io(void)
  */
 static unsigned int last_jiffy_time;
 
-#define TIMER4_TICKS_PER_JIFFY         ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
+#define TIMER4_TICKS_PER_JIFFY         DIV_ROUND_CLOSEST(CLOCK_TICK_RATE, HZ)
 
 static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id)
 {
@@ -362,8 +346,8 @@ void __init ep93xx_init_irq(void)
 {
        int gpio_irq;
 
-       vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
-       vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
+       vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
+       vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
 
        for (gpio_irq = gpio_to_irq(0);
             gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
@@ -384,6 +368,47 @@ void __init ep93xx_init_irq(void)
 }
 
 
+/*************************************************************************
+ * EP93xx System Controller Software Locked register handling
+ *************************************************************************/
+
+/*
+ * syscon_swlock prevents anything else from writing to the syscon
+ * block while a software locked register is being written.
+ */
+static DEFINE_SPINLOCK(syscon_swlock);
+
+void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&syscon_swlock, flags);
+
+       __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+       __raw_writel(val, reg);
+
+       spin_unlock_irqrestore(&syscon_swlock, flags);
+}
+EXPORT_SYMBOL(ep93xx_syscon_swlocked_write);
+
+void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
+{
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&syscon_swlock, flags);
+
+       val = __raw_readl(EP93XX_SYSCON_DEVCFG);
+       val |= set_bits;
+       val &= ~clear_bits;
+       __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+       __raw_writel(val, EP93XX_SYSCON_DEVCFG);
+
+       spin_unlock_irqrestore(&syscon_swlock, flags);
+}
+EXPORT_SYMBOL(ep93xx_devcfg_set_clear);
+
+
 /*************************************************************************
  * EP93xx peripheral handling
  *************************************************************************/
@@ -517,10 +542,8 @@ static struct platform_device ep93xx_eth_device = {
 
 void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
 {
-       if (copy_addr) {
-               memcpy(data->dev_addr,
-                       (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
-       }
+       if (copy_addr)
+               memcpy_fromio(data->dev_addr, EP93XX_ETHERNET_BASE + 0x50, 6);
 
        ep93xx_eth_data = *data;
        platform_device_register(&ep93xx_eth_device);
@@ -546,19 +569,125 @@ void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num)
        platform_device_register(&ep93xx_i2c_device);
 }
 
+
+/*************************************************************************
+ * EP93xx LEDs
+ *************************************************************************/
+static struct gpio_led ep93xx_led_pins[] = {
+       {
+               .name                   = "platform:grled",
+               .gpio                   = EP93XX_GPIO_LINE_GRLED,
+       }, {
+               .name                   = "platform:rdled",
+               .gpio                   = EP93XX_GPIO_LINE_RDLED,
+       },
+};
+
+static struct gpio_led_platform_data ep93xx_led_data = {
+       .num_leds       = ARRAY_SIZE(ep93xx_led_pins),
+       .leds           = ep93xx_led_pins,
+};
+
+static struct platform_device ep93xx_leds = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &ep93xx_led_data,
+       },
+};
+
+
+/*************************************************************************
+ * EP93xx pwm peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_pwm0_resource[] = {
+       {
+               .start  = EP93XX_PWM_PHYS_BASE,
+               .end    = EP93XX_PWM_PHYS_BASE + 0x10 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device ep93xx_pwm0_device = {
+       .name           = "ep93xx-pwm",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(ep93xx_pwm0_resource),
+       .resource       = ep93xx_pwm0_resource,
+};
+
+static struct resource ep93xx_pwm1_resource[] = {
+       {
+               .start  = EP93XX_PWM_PHYS_BASE + 0x20,
+               .end    = EP93XX_PWM_PHYS_BASE + 0x30 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device ep93xx_pwm1_device = {
+       .name           = "ep93xx-pwm",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(ep93xx_pwm1_resource),
+       .resource       = ep93xx_pwm1_resource,
+};
+
+void __init ep93xx_register_pwm(int pwm0, int pwm1)
+{
+       if (pwm0)
+               platform_device_register(&ep93xx_pwm0_device);
+
+       /* NOTE: EP9307 does not have PWMOUT1 (pin EGPIO14) */
+       if (pwm1)
+               platform_device_register(&ep93xx_pwm1_device);
+}
+
+int ep93xx_pwm_acquire_gpio(struct platform_device *pdev)
+{
+       int err;
+
+       if (pdev->id == 0) {
+               err = 0;
+       } else if (pdev->id == 1) {
+               err = gpio_request(EP93XX_GPIO_LINE_EGPIO14,
+                                  dev_name(&pdev->dev));
+               if (err)
+                       return err;
+               err = gpio_direction_output(EP93XX_GPIO_LINE_EGPIO14, 0);
+               if (err)
+                       goto fail;
+
+               /* PWM 1 output on EGPIO[14] */
+               ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_PONG);
+       } else {
+               err = -ENODEV;
+       }
+
+       return err;
+
+fail:
+       gpio_free(EP93XX_GPIO_LINE_EGPIO14);
+       return err;
+}
+EXPORT_SYMBOL(ep93xx_pwm_acquire_gpio);
+
+void ep93xx_pwm_release_gpio(struct platform_device *pdev)
+{
+       if (pdev->id == 1) {
+               gpio_direction_input(EP93XX_GPIO_LINE_EGPIO14);
+               gpio_free(EP93XX_GPIO_LINE_EGPIO14);
+
+               /* EGPIO[14] used for GPIO */
+               ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_PONG);
+       }
+}
+EXPORT_SYMBOL(ep93xx_pwm_release_gpio);
+
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)
 {
-       unsigned int v;
-
-       /*
-        * Disallow access to MaverickCrunch initially.
-        */
-       v = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
-       v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
-       __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
-       __raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);
+       /* Disallow access to MaverickCrunch initially */
+       ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA);
 
        ep93xx_gpio_init();
 
@@ -568,4 +697,5 @@ void __init ep93xx_init_devices(void)
 
        platform_device_register(&ep93xx_rtc_device);
        platform_device_register(&ep93xx_ohci_device);
+       platform_device_register(&ep93xx_leds);
 }