Signed-off-by: Russ Gorby <[email protected]>
---
RRG: providing an ioctl to perform modem reset under application control where
        the TTY is not hung up. The application then "knows" that it may need
        to reconfigure MUX mode for the modem and reconnect to channel devices.


 drivers/serial/ifx6x60.c          |   77 +++++++++++++++++++++++++++----------
 drivers/serial/ifx6x60.h          |    1 +
 include/linux/spi/ifx6x60_ioctl.h |    5 ++
 3 files changed, 63 insertions(+), 20 deletions(-)

diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
index b774faa..edcc712 100644
--- a/drivers/serial/ifx6x60.c
+++ b/drivers/serial/ifx6x60.c
@@ -670,6 +670,53 @@ static int ifx_spi_chars_in_buffer(struct tty_struct *tty)
 }
 
 /**
+ *     reset_modem
+ *
+ *     allows the modem to be reset under application control
+ *     does not generate tty hangup as with silent reset
+ */
+static int
+reset_modem(struct ifx_spi_device *ifx_dev)
+{
+       int ret;
+
+       set_bit(MR_START, &ifx_dev->mdm_reset_state);
+       gpio_set_value(ifx_dev->gpio.po, 0);
+       gpio_set_value(ifx_dev->gpio.reset, 0);
+       msleep(25);
+       gpio_set_value(ifx_dev->gpio.reset, 1);
+       msleep(1);
+       gpio_set_value(ifx_dev->gpio.po, 1);
+       msleep(1);
+       gpio_set_value(ifx_dev->gpio.po, 0);
+       ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
+                                test_bit(MR_COMPLETE,
+                                         &ifx_dev->mdm_reset_state),
+                                IFX_RESET_TIMEOUT);
+       if (!ret) {
+               dev_warn(&ifx_dev->spi_dev->dev,
+                        "Modem reset timeout: (state:%lx)",
+                        ifx_dev->mdm_reset_state);
+               ret = -1;
+               /*
+                * FIXME - sometime we don't see both interrupts from
+                *      RESET_OUT, but if we've seen the first one, then
+                *      that's sufficient currently
+                */
+               if (test_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state))
+                       ret = 0;
+       } else {
+               dev_dbg(&ifx_dev->spi_dev->dev,
+                       "Modem reset success: (state:%lx)",
+                       ifx_dev->mdm_reset_state);
+               ret = 0;
+       }
+       ifx_dev->mdm_reset_state = 0;
+
+       return ret;
+}
+
+/**
  *     ifx_spi_ioctl           -       special ioctl handler
  *     @tty: our tty device
  *     @file: the file handle used for the ioctl
@@ -686,6 +733,7 @@ static int ifx_spi_ioctl(struct tty_struct *tty, struct 
file *file,
        unsigned int cmd, unsigned long arg)
 {
        int nreset;
+       int ret;
        struct ifx_spi_device *ifx_dev = saved_ifx_dev;
 
        dev_dbg(&ifx_dev->spi_dev->dev,
@@ -722,6 +770,14 @@ static int ifx_spi_ioctl(struct tty_struct *tty, struct 
file *file,
                }
                break;
 
+       case IFX_MODEM_RESET:
+               if (!capable(CAP_SYS_RAWIO))
+                       return -EPERM;
+               ret = reset_modem(ifx_dev);
+               if (ret)
+                       return -ENXIO;
+               break;
+
        default:
                return -ENOIOCTLCMD;
        }
@@ -1551,26 +1607,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
         * delays are required on some platforms for the modem
         * to reset properly
         */
-       set_bit(MR_START, &ifx_dev->mdm_reset_state);
-       gpio_set_value(ifx_dev->gpio.po, 0);
-       gpio_set_value(ifx_dev->gpio.reset, 0);
-       msleep(25);
-       gpio_set_value(ifx_dev->gpio.reset, 1);
-       msleep(1);
-       gpio_set_value(ifx_dev->gpio.po, 1);
-       msleep(1);
-       gpio_set_value(ifx_dev->gpio.po, 0);
-       ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
-                                test_bit(MR_COMPLETE,
-                                         &ifx_dev->mdm_reset_state),
-                                IFX_RESET_TIMEOUT);
-       if (!ret)
-               dev_warn(&spi->dev, "Modem reset timeout: (state:%lx)",
-                        ifx_dev->mdm_reset_state);
-       else
-               dev_dbg(&spi->dev, "Modem reset success: (state:%lx)",
-                       ifx_dev->mdm_reset_state);
-       ifx_dev->mdm_reset_state = 0;
+       (void) reset_modem(ifx_dev);
 
        dev_dbg(&spi->dev, "Trying to get irq %x (%x)",
                gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev->gpio.srdy);
diff --git a/drivers/serial/ifx6x60.h b/drivers/serial/ifx6x60.h
index 130d572..734edb1 100644
--- a/drivers/serial/ifx6x60.h
+++ b/drivers/serial/ifx6x60.h
@@ -75,6 +75,7 @@ struct ifx_spi_device {
        struct ifx_spi_port_data *port_data;
        struct tasklet_struct io_work_tasklet;
        struct work_struct write_wakeup_work;
+       struct work_struct reset_work;
        unsigned long flags;
        int modem;
        dma_addr_t rx_dma;
diff --git a/include/linux/spi/ifx6x60_ioctl.h 
b/include/linux/spi/ifx6x60_ioctl.h
index e1a6057..8b8ed5b 100644
--- a/include/linux/spi/ifx6x60_ioctl.h
+++ b/include/linux/spi/ifx6x60_ioctl.h
@@ -48,5 +48,10 @@
  */
 #define IFX_SET_SPI_TRANSFER_SIZE      _IOW(IFX_SPI_MAGIC, 3, int)
 
+/*
+ * IFX_MODEM_RESET     - reset the modem (solicited reset)
+ */
+#define IFX_MODEM_RESET                _IO(IFX_SPI_MAGIC, 4)
+
 
 #endif /* _IFX6X60_IOCTL_H */
-- 
1.6.0.6

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to