Hi
We are using AM335x as a part of our product( SDK version is 7 ). I am facing an issue with the serial OMAP driver. The issue is specific to serial driver but I have to give out the below explanation to describe what we are trying to achieve( Apologize for the long description ).
We need to use either of our own custom driver in addition or OMAP serial driver for one of the UART ports ( UART 1 ) depending on the device status. I have done modifications to the am335x dts file to be able to load our driver and the OMAP serial driver using rmmod/insmod.
I built the OMAP driver as a new module and slightly modified it so that it doesn't interfere with the pre-existing OMAP driver used for other serial ports. Following is my patch for the OMAP driver:
--- /home/user/work/Apr10/diff/oldfile/omap-serial.c
+++ /home/user/work/Apr10/diff/newfile/omap-serial-alctpi.c
@@ -104,6 +104,8 @@
#define OMAP_UART_TCR_TRIG 0x0F
+#define TPI_DRIVER_NAME "omap_uart_tpi"
+
struct uart_omap_dma {
u8 uart_dma_tx;
u8 uart_dma_rx;
@@ -539,9 +541,18 @@
unsigned int type;
irqreturn_t ret = IRQ_NONE;
int max_count = 256;
+ unsigned int ier;
spin_lock(&up->port.lock);
pm_runtime_get_sync(up->dev);
+
+ /* Experimental
+ * Read IER register
+ */
+ ier = serial_in(up, UART_IER);
+ dev_printk(KERN_INFO, up->port.dev,
+ "###serial_omap_irq_1a - IER read value### - %d",
+ ier); //Manbir
do {
iir = serial_in(up, UART_IIR);
@@ -690,6 +701,7 @@
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
int retval;
+ unsigned int ier;
/*
* Allocate the IRQ
@@ -739,6 +751,14 @@
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
+
+ /* Experimental
+ * Read IER register
+ */
+ ier = serial_in(up, UART_IER);
+ dev_printk(KERN_INFO, up->port.dev,
+ "###serial_omap_startup - IER read value### - %d",
+ ier); //Manbir
/* Enable module level wake up */
up->wer = OMAP_UART_WER_MOD_WKUP;
@@ -1416,7 +1436,7 @@
static struct uart_driver serial_omap_reg = {
.owner = THIS_MODULE,
- .driver_name = "OMAP-SERIAL",
+ .driver_name = "OMAP-SERIAL-TPI",
.dev_name = OMAP_SERIAL_NAME,
.nr = OMAP_MAX_HSUART_PORTS,
.cons = OMAP_CONSOLE,
@@ -1558,7 +1578,7 @@
/* check for tx enable gpio */
up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
if (gpio_is_valid(up->rts_gpio)) {
- ret = gpio_request(up->rts_gpio, "omap-serial");
+ ret = gpio_request(up->rts_gpio, "omap_uart_tpi");
if (ret < 0)
return ret;
ret = gpio_direction_output(up->rts_gpio,
@@ -1615,7 +1635,7 @@
if (gpio_is_valid(omap_up_info->DTR_gpio) &&
omap_up_info->DTR_present) {
- ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
+ ret = gpio_request(omap_up_info->DTR_gpio, "omap_uart_tpi");
if (ret < 0)
return ret;
ret = gpio_direction_output(omap_up_info->DTR_gpio,
@@ -1728,7 +1748,18 @@
{
struct uart_omap_port *up = platform_get_drvdata(dev);
- pm_runtime_put_sync(up->dev);
+ // cancel any work in the workqueue and destroy it
+ cancel_work_sync(&up->qos_work);
+ destroy_workqueue(serial_omap_uart_wq);
+
+ // if RS485 was enabled for this port, de-assert and free the RTS GPIO pin
+ if ((up->rs485.flags & SER_RS485_ENABLED) && gpio_is_valid(up->rts_gpio))
+ {
+ gpio_set_value(up->rts_gpio, 0);
+ gpio_free(up->rts_gpio);
+ }
+
+ pm_runtime_put_sync(up->dev);
pm_runtime_disable(up->dev);
uart_remove_one_port(&serial_omap_reg, &up->port);
pm_qos_remove_request(&up->pm_qos_request);
@@ -1868,9 +1899,9 @@
#if defined(CONFIG_OF)
static const struct of_device_id omap_serial_of_match[] = {
- { .compatible = "ti,omap2-uart" },
- { .compatible = "ti,omap3-uart" },
- { .compatible = "ti,omap4-uart" },
+ { .compatible = "ti,omap3-uart-tpi" },
+ {},
+ {},
{},
};
MODULE_DEVICE_TABLE(of, omap_serial_of_match);
@@ -1880,7 +1911,7 @@
.probe = serial_omap_probe,
.remove = serial_omap_remove,
.driver = {
- .name = DRIVER_NAME,
+ .name = TPI_DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
.of_match_table = of_match_ptr(omap_serial_of_match),
},
Here is what i am trying to do:
The modified OMAP driver loads immediately after board start up. It works fine ( both TX/RX work on UART 1). I unload the driver using rmmod. I load it again insmod. On second time load of the driver only TX works and not RX. I get only one interrupt for RX and driver seems stuck there. I had to modify the driver ( basically free the GPIO pin ) to get it to this stage as well.
I did some further analysis and found the following( though nothing points to any issue ). The below is the observation for both first time and second time loading of the driver.
root@router:~# cat /sys/kernel/debug/gpio
GPIOs 0-31, gpio:
....
gpio-13 (omap_uart_tpi ) out lo
....
GPIOs 32-63, gpio:
...
GPIOs 64-95, gpio:
....
gpio-81 (omap_uart_cmnet ) out lo
gpio-91 (omap-serial ) out lo
gpio-93 (omap-serial ) out lo
....
So the GPIO is in correct state both the times the driver is loaded. Following is the UART description:
root@router:~# cat /proc/tty/driver/OMAP-SERIAL-TPI
serinfo:1.0 driver revision:
1: uart:OMAP UART1 mmio:0x48022000 irq:89 tx:0 rx:1 RTS|CTS|DTR|DSR|CD|RI
THE IRQ and UART base region etc are correct as well. In my above patch I print the contents of the IER UART register for debugging. Both the cases show value as 5 so this seems correct as well.
The issue is faced when I load the driver second time. It triggers interrupts only once and seems stuck there though the UART does physically receive data as measured by an RS485 COM probe. Could you give me a few hints as to what I should be checking to ensure UART was set to correct initialized state when the driver was loaded the second time?
Apologies once again for the long description. I am not a UART expert. If you need any more information, I would be happy tor provide.
Please feel free to suggest anything.
Thanks and Regards
Manbir Singh Jhawer