Some telephony middleware wants the ability to reset the modem directly

an ioctl was added to support this future need

Signed-off-by: Russ Gorby <russ.go...@intel.com>
---
 drivers/serial/ifx6x60.c          |   83 ++++++++++++++++++++++++++-----------
 drivers/serial/ifx6x60.h          |    1 +
 include/linux/spi/ifx6x60_ioctl.h |    5 ++
 3 files changed, 65 insertions(+), 24 deletions(-)

diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
index f84fd11..8ddac7c 100644
--- a/drivers/serial/ifx6x60.c
+++ b/drivers/serial/ifx6x60.c
@@ -668,6 +668,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
@@ -684,6 +731,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,
@@ -700,6 +748,14 @@ static int ifx_spi_ioctl(struct tty_struct *tty, struct 
file *file,
                        return -EFAULT;
                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;
        }
@@ -1278,11 +1334,9 @@ static irqreturn_t ifx_spi_reset_interrupt(int irq, void 
*dev)
                /* entered reset */
                ++ifx_dev->mdm_reset_cnt;
                set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
-               if (!solreset) {
-                       /* unsolicited reset  */
+               if (!solreset)
                        ++ifx_dev->mdm_reset_unsol;
-                       ifx_spi_ttyhangup(ifx_dev);
-               }
+               ifx_spi_ttyhangup(ifx_dev);
        } else {
                /* exited reset */
                clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
@@ -1524,26 +1578,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 fc8dd21..ed1c24d 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 3d773ab..3fa86d1 100644
--- a/include/linux/spi/ifx6x60_ioctl.h
+++ b/include/linux/spi/ifx6x60_ioctl.h
@@ -36,4 +36,9 @@
  */
 #define IFX_GET_SILENT_RESET   _IOR(IFX_SPI_MAGIC, 1, 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
MeeGo-kernel@lists.meego.com
http://lists.meego.com/listinfo/meego-kernel

Reply via email to