Russ Dill <russ.d...@gmail.com> writes:

> This patch causes the OMAP uarts to honor the sysfs power/wakeup file for
> IOPADs. Before the OMAP was always woken up from off mode on a rs232 signal
> change.
>
> This patch also creates a different platform device for each serial
> port so that the wakeup properties can be control per port.
>
> The patch is not in a complete state, but for my testing it was necessary
> to disable rs232 wakeup as allowing the signals to float in off mode by
> powering off the level converters was causing a wakeup event.
> ---
>  arch/arm/mach-omap2/serial.c |  165 
> ++++++++++++++++++++++++++++++++----------

In the process of playing with this I found some bugs the sysfs
implementation in this code that was exposed byt these patches.

Russ, I'll take these changes and incorporate them into my serial
fixes.

Thanks,

Kevin

>
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 0762165..95b047a 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -49,6 +49,7 @@ struct omap_uart_state {
>  
>       struct plat_serial8250_port *p;
>       struct list_head node;
> +     struct platform_device pdev;
>  
>  #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
>       int context_valid;
> @@ -63,10 +64,9 @@ struct omap_uart_state {
>  #endif
>  };
>  
> -static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
>  static LIST_HEAD(uart_list);
>  
> -static struct plat_serial8250_port serial_platform_data[] = {
> +static struct plat_serial8250_port serial_platform_data0[] = {
>       {
>               .membase        = IO_ADDRESS(OMAP_UART1_BASE),
>               .mapbase        = OMAP_UART1_BASE,
> @@ -76,6 +76,12 @@ static struct plat_serial8250_port serial_platform_data[] 
> = {
>               .regshift       = 2,
>               .uartclk        = OMAP24XX_BASE_BAUD * 16,
>       }, {
> +             .flags          = 0
> +     }
> +};
> +
> +static struct plat_serial8250_port serial_platform_data1[] = {
> +     {
>               .membase        = IO_ADDRESS(OMAP_UART2_BASE),
>               .mapbase        = OMAP_UART2_BASE,
>               .irq            = 73,
> @@ -84,6 +90,12 @@ static struct plat_serial8250_port serial_platform_data[] 
> = {
>               .regshift       = 2,
>               .uartclk        = OMAP24XX_BASE_BAUD * 16,
>       }, {
> +             .flags          = 0
> +     }
> +};
> +
> +static struct plat_serial8250_port serial_platform_data2[] = {
> +     {
>               .membase        = IO_ADDRESS(OMAP_UART3_BASE),
>               .mapbase        = OMAP_UART3_BASE,
>               .irq            = 74,
> @@ -197,6 +209,40 @@ static inline void omap_uart_save_context(struct 
> omap_uart_state *uart) {}
>  static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
>  #endif /* CONFIG_ARCH_OMAP3 */
>  
> +static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
> +{
> +     /* Set wake-enable bit */
> +     if (uart->wk_en && uart->wk_mask) {
> +             u32 v = __raw_readl(uart->wk_en);
> +             v |= uart->wk_mask;
> +             __raw_writel(v, uart->wk_en);
> +     }
> +
> +     /* Ensure IOPAD wake-enables are set */
> +     if (cpu_is_omap34xx() && uart->padconf) {
> +             u16 v = omap_ctrl_readw(uart->padconf);
> +             v |= OMAP3_PADCONF_WAKEUPENABLE0;
> +             omap_ctrl_writew(v, uart->padconf);
> +     }
> +}
> +
> +static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
> +{
> +     /* Clear wake-enable bit */
> +     if (uart->wk_en && uart->wk_mask) {
> +             u32 v = __raw_readl(uart->wk_en);
> +             v &= ~uart->wk_mask;
> +             __raw_writel(v, uart->wk_en);
> +     }
> +
> +     /* Ensure IOPAD wake-enables are cleared */
> +     if (cpu_is_omap34xx() && uart->padconf) {
> +             u16 v = omap_ctrl_readw(uart->padconf);
> +             v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
> +             omap_ctrl_writew(v, uart->padconf);
> +     }
> +}
> +
>  static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
>                                         int enable)
>  {
> @@ -220,6 +266,11 @@ static inline void omap_uart_restore(struct 
> omap_uart_state *uart)
>  
>  static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
>  {
> +     if (device_may_wakeup(&uart->pdev.dev))
> +             omap_uart_enable_wakeup(uart);
> +     else
> +             omap_uart_disable_wakeup(uart);
> +
>       if (!uart->clocked)
>               return;
>  
> @@ -290,6 +341,7 @@ void omap_uart_resume_idle(int num)
>                       if (__raw_readl(uart->wk_st) & uart->wk_mask)
>                               omap_uart_block_sleep(uart);
>  
> +                     omap_uart_enable_wakeup(uart);
>                       return;
>               }
>       }
> @@ -300,6 +352,7 @@ void omap_uart_prepare_suspend(void)
>       struct omap_uart_state *uart;
>  
>       list_for_each_entry(uart, &uart_list, node) {
> +             omap_uart_enable_wakeup(uart);
>               omap_uart_allow_sleep(uart);
>       }
>  }
> @@ -343,16 +396,13 @@ static irqreturn_t omap_uart_interrupt(int irq, void 
> *dev_id)
>       return IRQ_NONE;
>  }
>  
> -static u32 sleep_timeout = DEFAULT_TIMEOUT;
> -
>  static void omap_uart_idle_init(struct omap_uart_state *uart)
>  {
> -     u32 v;
>       struct plat_serial8250_port *p = uart->p;
>       int ret;
>  
>       uart->can_sleep = 0;
> -     uart->timeout = sleep_timeout;
> +     uart->timeout = DEFAULT_TIMEOUT;
>       setup_timer(&uart->timer, omap_uart_idle_timer,
>                   (unsigned long) uart);
>       mod_timer(&uart->timer, jiffies + uart->timeout);
> @@ -410,22 +460,6 @@ static void omap_uart_idle_init(struct omap_uart_state 
> *uart)
>               uart->padconf = 0;
>       }
>  
> -     /* Set wake-enable bit */
> -     if (uart->wk_en && uart->wk_mask) {
> -             v = __raw_readl(uart->wk_en);
> -             v |= uart->wk_mask;
> -             __raw_writel(v, uart->wk_en);
> -     }
> -
> -     /* Ensure IOPAD wake-enables are set */
> -     if (cpu_is_omap34xx() && uart->padconf) {
> -             u16 v;
> -
> -             v = omap_ctrl_readw(uart->padconf);
> -             v |= OMAP3_PADCONF_WAKEUPENABLE0;
> -             omap_ctrl_writew(v, uart->padconf);
> -     }
> -
>       p->flags |= UPF_SHARE_IRQ;
>       ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
>                         "serial idle", (void *)uart);
> @@ -450,23 +484,30 @@ static ssize_t sleep_timeout_show(struct kobject *kobj,
>                                 struct kobj_attribute *attr,
>                                 char *buf)
>  {
> -     return sprintf(buf, "%u\n", sleep_timeout / HZ);
> +     struct device *dev = container_of(kobj, struct device, kobj);
> +     struct platform_device *pdev = container_of(dev,
> +                                     struct platform_device, dev);
> +     struct omap_uart_state *uart = container_of(pdev,
> +                                     struct omap_uart_state, pdev);
> +     return sprintf(buf, "%u\n", uart->timeout / HZ);
>  }
>  
>  static ssize_t sleep_timeout_store(struct kobject *kobj,
>                                  struct kobj_attribute *attr,
>                                  const char *buf, size_t n)
>  {
> -     struct omap_uart_state *uart;
> +     struct device *dev = container_of(kobj, struct device, kobj);
> +     struct platform_device *pdev = container_of(dev,
> +                                     struct platform_device, dev);
> +     struct omap_uart_state *uart = container_of(pdev,
> +                                     struct omap_uart_state, pdev);
>       unsigned int value;
>  
>       if (sscanf(buf, "%u", &value) != 1) {
>               printk(KERN_ERR "sleep_timeout_store: Invalid value\n");
>               return -EINVAL;
>       }
> -     sleep_timeout = value * HZ;
> -     list_for_each_entry(uart, &uart_list, node)
> -             uart->timeout = sleep_timeout;
> +     uart->timeout = value * HZ;
>       return n;
>  }
>  
> @@ -477,6 +518,34 @@ static struct kobj_attribute sleep_timeout_attr =
>  static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
>  #endif /* CONFIG_PM */
>  
> +static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = {
> +     {
> +             .pdev = {
> +                     .name                   = "serial8250",
> +                     .id                     = PLAT8250_DEV_PLATFORM,
> +                     .dev                    = {
> +                             .platform_data  = serial_platform_data0,
> +                     },
> +             },
> +     }, {
> +             .pdev = {
> +                     .name                   = "serial8250",
> +                     .id                     = PLAT8250_DEV_PLATFORM1,
> +                     .dev                    = {
> +                             .platform_data  = serial_platform_data1,
> +                     },
> +             },
> +     }, {
> +             .pdev = {
> +                     .name                   = "serial8250",
> +                     .id                     = PLAT8250_DEV_PLATFORM2,
> +                     .dev                    = {
> +                             .platform_data  = serial_platform_data2,
> +                     },
> +             },
> +     },
> +};
> +
>  void __init omap_serial_init(void)
>  {
>       int i;
> @@ -495,8 +564,8 @@ void __init omap_serial_init(void)
>               return;
>  
>       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
> -             struct plat_serial8250_port *p = serial_platform_data + i;
>               struct omap_uart_state *uart = &omap_uart[i];
> +             struct plat_serial8250_port *p = uart->pdev.dev.platform_data;
>  
>               if (!(info->enabled_uarts & (1 << i))) {
>                       p->membase = NULL;
> @@ -532,25 +601,43 @@ void __init omap_serial_init(void)
>       }
>  }
>  
> -static struct platform_device serial_device = {
> -     .name                   = "serial8250",
> -     .id                     = PLAT8250_DEV_PLATFORM,
> -     .dev                    = {
> -             .platform_data  = serial_platform_data,
> -     },
> -};
> -
>  static int __init omap_init(void)
>  {
>       int ret;
> +     int i;
>  
> -     ret = platform_device_register(&serial_device);
> +     for (i = 0; i < ARRAY_SIZE(omap_uart); i++) {
> +             ret = platform_device_register(&omap_uart[i].pdev);
> +             if (ret < 0)
> +                     goto device_err;
> +             if ((cpu_is_omap34xx() && omap_uart[i].padconf) ||
> +                 (omap_uart[i].wk_en && omap_uart[i].wk_mask)) {
> +                     printk(KERN_ERR "%s: Setting init_wakeup\n", __func__);
> +                     device_init_wakeup(&omap_uart[i].pdev.dev, true);
> +             }
> +     }
>  
>  #ifdef CONFIG_PM
> -     if (!ret)
> -             ret = sysfs_create_file(&serial_device.dev.kobj,
> +     for (i = 0; i < ARRAY_SIZE(omap_uart); i++) {
> +             ret = sysfs_create_file(&omap_uart[i].pdev.dev.kobj,
>                                       &sleep_timeout_attr.attr);
> +             if (ret < 0)
> +                     goto sysfs_err;
> +     }
> +#endif
> +     return ret;
> +
> +#ifdef CONFIG_PM
> +sysfs_err:
> +     for (i--; i >= 0; i--)
> +             sysfs_remove_file(&omap_uart[i].pdev.dev.kobj,
> +                             &sleep_timeout_attr.attr);
> +     i = ARRAY_SIZE(omap_uart);
>  #endif
> +
> +device_err:
> +     for (i--; i >= 0; i--)
> +             platform_device_unregister(&omap_uart[i].pdev);
>       return ret;
>  }
>  arch_initcall(omap_init);
> -- 
> 1.6.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to