andrzej-kaczmarek closed pull request #1321: Add simple PM for UART device 
driver
URL: https://github.com/apache/mynewt-core/pull/1321
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/hw/drivers/uart/include/uart/uart.h 
b/hw/drivers/uart/include/uart/uart.h
index 6bd40a9128..ec79937418 100644
--- a/hw/drivers/uart/include/uart/uart.h
+++ b/hw/drivers/uart/include/uart/uart.h
@@ -72,12 +72,6 @@ struct uart_driver_funcs {
     void (*uf_blocking_tx)(struct uart_dev *, uint8_t);
 };
 
-struct uart_dev {
-    struct os_dev ud_dev;
-    struct uart_driver_funcs ud_funcs;
-    void *ud_priv;
-};
-
 /*
  * ***Note that these enum values must match what hw/hal/hal_uart.h***
  */
@@ -92,6 +86,14 @@ enum uart_flow_ctl {
     UART_FLOW_CTL_RTS_CTS = 1   /* RTS/CTS */
 };
 
+struct uart_conf_port {
+    uint32_t uc_speed;          /* baudrate in bps */
+    uint8_t uc_databits;        /* number of data bits */
+    uint8_t uc_stopbits;        /* number of stop bits */
+    enum uart_parity uc_parity;
+    enum uart_flow_ctl uc_flow_ctl;
+};
+
 struct uart_conf {
     uint32_t uc_speed;          /* baudrate in bps */
     uint8_t uc_databits;        /* number of data bits */
@@ -104,6 +106,13 @@ struct uart_conf {
     void *uc_cb_arg;
 };
 
+struct uart_dev {
+    struct os_dev ud_dev;
+    struct uart_driver_funcs ud_funcs;
+    struct uart_conf_port ud_conf_port;
+    void *ud_priv;
+};
+
 /*
  * Tell driver that more data has been queued, and that the driver should
  * start asking for it.
diff --git a/hw/drivers/uart/uart_hal/src/uart_hal.c 
b/hw/drivers/uart/uart_hal/src/uart_hal.c
index 609c473d72..1ff094eb9a 100644
--- a/hw/drivers/uart/uart_hal/src/uart_hal.c
+++ b/hw/drivers/uart/uart_hal/src/uart_hal.c
@@ -82,6 +82,13 @@ uart_hal_open(struct os_dev *odev, uint32_t wait, void *arg)
     if (odev->od_flags & OS_DEV_F_STATUS_OPEN) {
         return OS_EBUSY;
     }
+
+    dev->ud_conf_port.uc_databits = uc->uc_databits;
+    dev->ud_conf_port.uc_flow_ctl = uc->uc_flow_ctl;
+    dev->ud_conf_port.uc_parity = uc->uc_parity;
+    dev->ud_conf_port.uc_speed = uc->uc_speed;
+    dev->ud_conf_port.uc_stopbits = uc->uc_stopbits;
+
     rc = hal_uart_init_cbs(uart_hal_dev_get_id(dev), uc->uc_tx_char, 
uc->uc_tx_done,
                            uc->uc_rx_char, uc->uc_cb_arg);
     if (rc) {
@@ -107,6 +114,55 @@ uart_hal_close(struct os_dev *odev)
     if (rc) {
         return OS_EINVAL;
     }
+
+    return OS_OK;
+}
+
+static int
+uart_hal_suspend(struct os_dev *odev, os_time_t suspend_at, int force)
+{
+    struct uart_dev *dev = (struct uart_dev *)odev;
+    int rc;
+
+    /*
+     * XXX this should not be used as an example on how to add suspend/resume
+     * to os_dev since it's just provisional implementation to allow disable
+     * and enable UART to have some basic power saving. The whole 
suspend/resume
+     * framework probably should be revised and proper implementation added 
here
+     * then.
+     */
+
+    /*
+     * It seems as for now we have no way of making decision whether we can
+     * suspend or not, so let's just allow force suspend at "now".
+     */
+    if (OS_TIME_TICK_GT(suspend_at, os_time_get()) || !force) {
+        return OS_EINVAL;
+    }
+
+    rc = hal_uart_close(uart_hal_dev_get_id(dev));
+    if (rc) {
+        return OS_EINVAL;
+    }
+
+    return OS_OK;
+}
+
+static int
+uart_hal_resume(struct os_dev *odev)
+{
+    struct uart_dev *dev = (struct uart_dev *)odev;
+    struct uart_conf_port *ucp = &dev->ud_conf_port;
+    int rc;
+
+    rc = hal_uart_config(uart_hal_dev_get_id(dev), ucp->uc_speed,
+                         ucp->uc_databits, ucp->uc_stopbits,
+                         (enum hal_uart_parity)ucp->uc_parity,
+                         (enum hal_uart_flow_ctl)ucp->uc_flow_ctl);
+    if (rc) {
+        return OS_EINVAL;
+    }
+
     return OS_OK;
 }
 
@@ -128,6 +184,8 @@ uart_hal_init(struct os_dev *odev, void *arg)
     uart_hal_dev_set_id(dev, ch - '0');
 
     OS_DEV_SETHANDLERS(odev, uart_hal_open, uart_hal_close);
+    odev->od_handlers.od_suspend = uart_hal_suspend;
+    odev->od_handlers.od_resume = uart_hal_resume;
 
     dev->ud_funcs.uf_start_tx = uart_hal_start_tx;
     dev->ud_funcs.uf_start_rx = uart_hal_start_rx;
diff --git a/kernel/os/include/os/os_dev.h b/kernel/os/include/os/os_dev.h
index b8c8647e96..c05f6f251f 100644
--- a/kernel/os/include/os/os_dev.h
+++ b/kernel/os/include/os/os_dev.h
@@ -157,16 +157,7 @@ struct os_dev {
  *
  * @return 0 on success, non-zero error code on failure.
  */
-static inline int
-os_dev_suspend(struct os_dev *dev, os_time_t suspend_t, uint8_t force)
-{
-    if (dev->od_handlers.od_suspend == NULL) {
-        return (0);
-    } else {
-        return (dev->od_handlers.od_suspend(dev, suspend_t, force));
-    }
-}
-
+int os_dev_suspend(struct os_dev *dev, os_time_t suspend_t, uint8_t force);
 
 /**
  * Resume the device operation.
@@ -175,15 +166,7 @@ os_dev_suspend(struct os_dev *dev, os_time_t suspend_t, 
uint8_t force)
  *
  * @return 0 on success, non-zero error code on failure.
  */
-static inline int
-os_dev_resume(struct os_dev *dev)
-{
-    if (dev->od_handlers.od_resume == NULL) {
-        return (0);
-    } else {
-        return (dev->od_handlers.od_resume(dev));
-    }
-}
+int os_dev_resume(struct os_dev *dev);
 
 /**
  * Create a new device in the kernel.
diff --git a/kernel/os/src/os_dev.c b/kernel/os/src/os_dev.c
index 0ec5ff8b90..9c10ed160f 100644
--- a/kernel/os/src/os_dev.c
+++ b/kernel/os/src/os_dev.c
@@ -247,7 +247,7 @@ os_dev_close(struct os_dev *dev)
 
     OS_ENTER_CRITICAL(sr);
     if (--dev->od_open_ref == 0) {
-        dev->od_flags &= ~OS_DEV_F_STATUS_OPEN;
+        dev->od_flags &= ~(OS_DEV_F_STATUS_OPEN | OS_DEV_F_STATUS_SUSPENDED);
     }
     OS_EXIT_CRITICAL(sr);
 
@@ -256,6 +256,64 @@ os_dev_close(struct os_dev *dev)
     return (rc);
 }
 
+int
+os_dev_suspend(struct os_dev *dev, os_time_t suspend_t, uint8_t force)
+{
+    os_sr_t sr;
+    int rc;
+
+    OS_ENTER_CRITICAL(sr);
+    if (!(dev->od_flags & OS_DEV_F_STATUS_OPEN)) {
+        OS_EXIT_CRITICAL(sr);
+        return OS_EINVAL;
+    }
+    if (dev->od_flags & OS_DEV_F_STATUS_SUSPENDED) {
+        OS_EXIT_CRITICAL(sr);
+        return OS_OK;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    if (dev->od_handlers.od_suspend) {
+        rc = dev->od_handlers.od_suspend(dev, suspend_t, force);
+        if (rc) {
+            return rc;
+        }
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    dev->od_flags |= OS_DEV_F_STATUS_SUSPENDED;
+    OS_EXIT_CRITICAL(sr);
+
+    return OS_OK;
+}
+
+int
+os_dev_resume(struct os_dev *dev)
+{
+    os_sr_t sr;
+    int rc;
+
+    OS_ENTER_CRITICAL(sr);
+    if (!(dev->od_flags & OS_DEV_F_STATUS_SUSPENDED)) {
+        OS_EXIT_CRITICAL(sr);
+        return OS_EINVAL;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    if (dev->od_handlers.od_resume) {
+        rc = dev->od_handlers.od_resume(dev);
+        if (rc) {
+            return rc;
+        }
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    dev->od_flags &= ~OS_DEV_F_STATUS_SUSPENDED;
+    OS_EXIT_CRITICAL(sr);
+
+    return OS_OK;
+}
+
 void
 os_dev_reset(void)
 {


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to