[FE training-materials-updates] kernel labs: serial iomem ready

Michael Opdenacker michael.opdenacker at free-electrons.com
Thu Oct 3 21:38:15 CEST 2013


Repository : git://git.free-electrons.com/training-materials.git

On branch  : kernel-ng
Link       : http://git.free-electrons.com/training-materials/commit/?id=2d4841279620a3633e1759957cdc85cfc08e2780

>---------------------------------------------------------------

commit 2d4841279620a3633e1759957cdc85cfc08e2780
Author: Michael Opdenacker <michael.opdenacker at free-electrons.com>
Date:   Thu Oct 3 21:37:24 2013 +0200

    kernel labs: serial iomem ready
    
    Signed-off-by: Michael Opdenacker <michael.opdenacker at free-electrons.com>


>---------------------------------------------------------------

2d4841279620a3633e1759957cdc85cfc08e2780
 labs/kernel-serial-iomem/kernel-serial-iomem.tex |   77 ++++++++++++++++++++--
 1 file changed, 70 insertions(+), 7 deletions(-)

diff --git a/labs/kernel-serial-iomem/kernel-serial-iomem.tex b/labs/kernel-serial-iomem/kernel-serial-iomem.tex
index 192ed20..5df5631 100644
--- a/labs/kernel-serial-iomem/kernel-serial-iomem.tex
+++ b/labs/kernel-serial-iomem/kernel-serial-iomem.tex
@@ -198,7 +198,13 @@ in subsequent steps of the \code{probe()} routine.
 
 Make sure that your updated driver compiles, loads and unloads well.
 
-\section{Accessing device registers}
+\section{Device initialization}
+
+Now that we have a virtual address to access registers, we are ready to
+configure a few registers which will allow us to enable the UART
+devices. Of course, this will be done in the \code{probe()} routine.
+
+\subsection{Accessing device registers}
 
 As we will have multiple registers to read, create a \code{reg_read()}
 routine, returning an \code{unsigned int} value, and  taking a \code{dev}
@@ -208,6 +214,8 @@ offset.
 In this function, read a word at the base virtual address
 for the device plus the offset multiplied by 4, and return this value.
 
+Note that all the I/O registers of the AM335x SoC are 32 bits wide.
+
 Create a similar \code{reg_write()} routine, writing an integer value
 at a given integer offset from the device base virtual address.
 
@@ -216,6 +224,61 @@ several types of serial drivers (see
 \code{include/uapi/linux/serial_reg.h}). This explains why they are not
 completely ready to use and we have to multiply them by 4 for OMAP SoCs.
 
+We are now ready to read and write registers!
+
+\subsection{Power management initialization}
+
+Add the below lines:
+
+\begin{verbatim}
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+\end{verbatim}
+
+And add the below line to the \code{remove()} routine:
+
+\begin{verbatim}
+	pm_runtime_disable(&pdev->dev);
+\end{verbatim}
+
+\subsection{Line and baud rate configuration}
+
+After these lines, let's add code to initialize the line
+and configure the baud rate. This shows how to get a special
+property from the device tree, in this case \code{clock-frequency}:
+
+\begin{verbatim}
+        /* Configure the baud rate to 115200 */
+
+        of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+                             &uartclk);
+        baud_divisor = uartclk / 16 / 115200;
+        reg_write(dev, 0x07, UART_OMAP_MDR1);
+        reg_write(dev, 0x00, UART_LCR);
+        reg_write(dev, UART_LCR_DLAB, UART_LCR);
+        reg_write(dev, baud_divisor & 0xff, UART_DLL);
+        reg_write(dev, (baud_divisor >> 8) & 0xff, UART_DLM);
+	reg_write(dev, UART_LCR_WLEN8, UART_LCR);
+\end{verbatim}
+
+Declare \code{baud_divisor} and \code{uartclk} as \code{unsigned int}.
+
+\subsection{Soft reset}
+
+The last thing to do is to request a software reset:
+
+\begin{verbatim}
+        /* Soft reset */
+        reg_write(dev, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, UART_FCR);
+        reg_write(dev, 0x00, UART_OMAP_MDR1);
+\end{verbatim}
+
+We are now ready to transmit characters over the serial ports!
+
+If you have a bit of spare time, you can look at section 19 of the
+AM335x TRM for details about how to use the UART ports, to understand
+better what we are doing here.
+ 
 \section{Standalone write routine}
 
 Implement a C routine taking a pointer to an \code{feserial_dev}
@@ -230,8 +293,6 @@ this character to the serial port, using the following steps:
 \item Write the character to the \code{UART_TX} register.
 \end{enumerate}
 
-Note that all the I/O registers of the AM335x SoC are 32 bits wide.
-
 Add a call to this routine from your module \code{probe()} function,
 and recompile your module.
 
@@ -246,11 +307,13 @@ Load your module on the target. You should see the
 corresponding character in the new \code{picocom} installed,
 showing what was written to UART2.
 
+You can also check that you also get the same character on UART4
+(just connect to the UART4 pins instead of the UART2 ones).
+
 \section{Driver sanity check}
 
 Remove your module and try to load it again. If the second attempt to
 load the module fails, it is probably because your driver doesn't
-properly free the resources it allocated or register, either at module
-exit time, or after a failing during the module init function. Check
-and fix your module init and exit functions if you have such a
-problem.
+properly free the resources it allocated or registered, either at module
+exit time, or after a failure during the module \code{probe()} function. Check
+and fix your module code if you have such problems.



More information about the training-materials-updates mailing list