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