From 3ddd85624735a0c730672a5bc440adffecc7725c Mon Sep 17 00:00:00 2001 From: Mykyta Dorokhin Date: Mon, 19 Sep 2016 23:07:26 +0300 Subject: mtp: set proper timings for the radio power up/down command; remove radio reset on the module loading --- io-module/mtp.c | 222 +++++++++++++++++++++++++++++++++++------------------ io-module/mts_io.c | 10 +-- 2 files changed, 149 insertions(+), 83 deletions(-) diff --git a/io-module/mtp.c b/io-module/mtp.c index 9726b86..e034da4 100644 --- a/io-module/mtp.c +++ b/io-module/mtp.c @@ -1,5 +1,3 @@ -#define MTP_RADIO_RESET - static struct gpio_pin gpio_pins_mtp_0_0[] = { { .name = "ETH_EN", @@ -91,16 +89,48 @@ static struct gpio_pin gpio_pins_mtp_0_0[] = { { }, }; +static int radio_unconditional_shutdown_mtp(void) +{ + struct gpio_pin *rst_pin = gpio_pin_by_attr_name("radio-reset"); + struct gpio_pin *pwrmon_pin = gpio_pin_by_attr_name("radio-power-monitor"); + int value; + int i; + + if (!rst_pin || !pwrmon_pin) { + return -ENODEV; + } + + // To unconditionally shutdown the LE910, the pad HW_SHUTDOWN* must + // be tied low for at least 200 milliseconds and then released. + reset_gpio_pin(rst_pin, 500, 0); + + msleep(100); + + // Wait for the power off + for (i = 0; i < 5; i++) { + value = gpio_get_value(pwrmon_pin->pin.gpio); + if (value != 0) { + log_warning("radio is still on."); + msleep(500); + continue; + } + log_warning("radio has been shutdown unconditionally"); + break; + } + + return 0; +} -#ifdef MTP_RADIO_RESET /* radio control (power/reset) for mtp */ static int radio_off_mtp(void) { - int value; + // ref: Telit_LE910_Hardware_User_Guide_r6.pdf (4.3.2 Hardware Shutdown) struct gpio_pin *pwrmon_pin = gpio_pin_by_attr_name("radio-power-monitor"); struct gpio_pin *onoff_pin = gpio_pin_by_attr_name("radio-power"); struct gpio_pin *rst_pin = gpio_pin_by_attr_name("radio-reset"); + int value; + int i; if (!onoff_pin || !pwrmon_pin || !rst_pin) { return -ENODEV; @@ -108,45 +138,52 @@ static int radio_off_mtp(void) value = gpio_get_value(pwrmon_pin->pin.gpio); if(value == 0) { - log_error("radio is already off"); - return -EINVAL; + log_warning("radio is already off"); + return 0; } - // drive on/off pin low for at least 3 sec - log_info("shutting down radio"); - gpio_set_value(onoff_pin->pin.gpio, 0); - - msleep(3500); - - // set on/off pin high - gpio_set_value(onoff_pin->pin.gpio, 1); - - msleep(200); - - // check that power is low - value = gpio_get_value(pwrmon_pin->pin.gpio); - if(value != 0) { - log_warning("radio is still on. performing radio reset."); - //Perform Hard Reset - gpio_set_value(rst_pin->pin.gpio, 0); - - msleep(500); + log_info("turning off radio"); + + // To turn OFF LE910 the pad ON/OFF# must be tied low for at least 2 seconds and then + // released. Same circuitry and timing for the power on must be used. When the hold + // time of ON/OFF# is above 2 seconds, LE910 goes into the finalization state and + // finally will shut down PWRMON at the end of this state. The period of the + // finalization state can differ according to the situation in which the LE910 is so it + // cannot be fixed definitely. Normally it will be above 15 seconds later from releasing + // ON/OFF# and DTE should monitor the status of PWRMON to see the actual power off. + + reset_gpio_pin(onoff_pin, 2500, 0); + + value = 0; + for (i = 0; i < 15; i++) { + // check that power is low + value = gpio_get_value(pwrmon_pin->pin.gpio); + if (value != 0) { + log_info("radio is still on. keep waiting..."); + msleep(2000); + continue; + } + break; + } - // set pin high - gpio_set_value(rst_pin->pin.gpio, 1); - } else { + if (value == 0) { log_info("radio has been shut down"); } + else { + log_warning("radio is still on. performing unconditional shutdown..."); + radio_unconditional_shutdown_mtp(); + } return 0; } static int radio_on_mtp(void) { - int value; + // ref: Telit_LE910_Hardware_User_Guide_r6.pdf struct gpio_pin *pwrmon_pin = gpio_pin_by_attr_name("radio-power-monitor"); struct gpio_pin *onoff_pin = gpio_pin_by_attr_name("radio-power"); struct gpio_pin *rst_pin = gpio_pin_by_attr_name("radio-reset"); + int value; if (!onoff_pin || !pwrmon_pin || !rst_pin) { return -ENODEV; @@ -154,32 +191,24 @@ static int radio_on_mtp(void) value = gpio_get_value(pwrmon_pin->pin.gpio); if(value != 0) { - log_error("radio is already on"); - return -EINVAL; + log_warning("radio is already on"); + return 0; } - // drive on/off pin low for at least 5 sec log_info("turning on radio"); - gpio_set_value(onoff_pin->pin.gpio, 0); - - msleep(5500); - // set on/off pin high + // drive on/off pin high for at least 1 seconoff_pin gpio_set_value(onoff_pin->pin.gpio, 1); + msleep(1000); - msleep(200); + // 1) drive on/off pin low for < 2 sec + // 2) drive on/off pin high + reset_gpio_pin(onoff_pin, 1500, 0); // check that power is high value = gpio_get_value(pwrmon_pin->pin.gpio); if(value == 0) { - log_warning("radio is still off. performing radio reset"); - //Perform Hard Reset - gpio_set_value(rst_pin->pin.gpio, 0); - - msleep(500); - - // set pin high - gpio_set_value(rst_pin->pin.gpio, 1); + log_warning("radio is still off."); } else { log_info("radio has been turned on"); } @@ -189,31 +218,35 @@ static int radio_on_mtp(void) static int radio_reset_mtp(void) { - struct gpio_pin *onoff_pin = gpio_pin_by_attr_name("radio-power"); + // ref: Telit_LE910_Hardware_User_Guide_r6.pdf struct gpio_pin *rst_pin = gpio_pin_by_attr_name("radio-reset"); + struct gpio_pin *onoff_pin = gpio_pin_by_attr_name("radio-power"); - if (!rst_pin || !onoff_pin) { + if (!rst_pin || !onoff_pin) { return -ENODEV; } - // drive reset pin low for 500ms - gpio_set_value(rst_pin->pin.gpio, 0); + // + // Unconditional shutdown + // - msleep(500); + log_info("performing unconditional radio shutdown"); - // set pin high - gpio_set_value(rst_pin->pin.gpio, 1); + radio_unconditional_shutdown_mtp(); - // wait for 2 sec before toggling on/off pin - msleep(2000); + // + // Turning on radio + // + log_info("turning on radio"); - // drive on/off pin low for 6 sec - gpio_set_value(onoff_pin->pin.gpio, 0); + // drive on/off pin high for at least 1 sec + gpio_set_value(onoff_pin->pin.gpio, 1); + msleep(1000); - msleep(6000); - // set on/off pin high - gpio_set_value(onoff_pin->pin.gpio, 1); + // drive on/off pin low for < 2 sec + // drive on/off pin high + reset_gpio_pin(onoff_pin, 1500, 0); return 0; } @@ -227,15 +260,14 @@ static ssize_t mts_attr_store_radio_power_mtp(struct device *dev, if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } + + mutex_lock(&mts_io_mutex); if (value == 0) { - mutex_lock(&mts_io_mutex); err = radio_off_mtp(); - mutex_unlock(&mts_io_mutex); } else { - mutex_lock(&mts_io_mutex); err = radio_on_mtp(); - mutex_unlock(&mts_io_mutex); } + mutex_unlock(&mts_io_mutex); if (err) { return err; @@ -253,6 +285,7 @@ static ssize_t mts_attr_store_radio_reset_mtp(struct device *dev, if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } + if (value != 0) { return -EINVAL; } @@ -279,8 +312,6 @@ static ssize_t mts_attr_store_radio_reset_mtp(struct device *dev, radio_reset_timer_is_start = 1; } - log_info("radio is reset\n"); - mutex_lock(&mts_io_mutex); err = radio_reset_mtp(); @@ -309,15 +340,63 @@ static ssize_t mts_attr_show_radio_power_mtp(struct device *dev, return sprintf(buf, "%d\n", value); } +static int lora_reset_mtp(void) +{ + struct gpio_pin *rst_pin = gpio_pin_by_attr_name("lora-reset"); + + if (!rst_pin) { + return -ENODEV; + } + + /* + * drive the reset pin low, set pin high for 100ns, drive pin low + */ + gpio_set_value(rst_pin->pin.gpio, 0); + + gpio_set_value(rst_pin->pin.gpio, 1); + + msleep(1); + + gpio_set_value(rst_pin->pin.gpio, 0); + + msleep(100); + + return 0; +} + +static ssize_t mts_attr_store_lora_reset_mtp(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int value; + int err; + + if (sscanf(buf, "%i", &value) != 1) { + return -EINVAL; + } + + log_info("performing lora reset"); + + mutex_lock(&mts_io_mutex); + + err = lora_reset_mtp(); + + mutex_unlock(&mts_io_mutex); + + if (err) { + return err; + } + + return count; +} + static DEVICE_ATTR_MTS(dev_attr_radio_reset_mtp, "radio-reset", mts_attr_show_gpio_pin, mts_attr_store_radio_reset_mtp); static DEVICE_ATTR_MTS(dev_attr_radio_power_mtp, "radio-power", mts_attr_show_radio_power_mtp, mts_attr_store_radio_power_mtp); -#endif // MTP_RADIO_RESET static DEVICE_ATTR_MTS(dev_attr_lora_reset_mtp, "lora-reset", - mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + mts_attr_show_gpio_pin, mts_attr_store_lora_reset_mtp); static DEVICE_ATTR_MTS(dev_attr_eth_enabled_mtp, "eth-enabled", mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); @@ -342,13 +421,10 @@ static struct attribute *mtp_0_0_platform_attributes[] = { &dev_attr_eth_enabled_mtp.attr, -#ifdef MTP_RADIO_RESET + &dev_attr_lora_reset_mtp.attr, + &dev_attr_radio_power_mtp.attr, &dev_attr_radio_reset_mtp.attr, -#else - &dev_attr_radio_power.attr, - &dev_attr_radio_reset.attr, -#endif &dev_attr_radio_reset_backoffs.attr, &dev_attr_radio_reset_backoff_index.attr, @@ -359,8 +435,6 @@ static struct attribute *mtp_0_0_platform_attributes[] = { &dev_attr_led_lora_gpio_mtp.attr, &dev_attr_led_wifi_gpio_mtp.attr, - &dev_attr_lora_reset_mtp.attr, - NULL, }; diff --git a/io-module/mts_io.c b/io-module/mts_io.c index 0d2457d..f3b79d5 100644 --- a/io-module/mts_io.c +++ b/io-module/mts_io.c @@ -47,7 +47,7 @@ #include "mts_io.h" -#define DRIVER_VERSION "v1.3.2" +#define DRIVER_VERSION "v1.3.3" #define DRIVER_AUTHOR "James Maki " #define DRIVER_DESC "MTS-IO Controller" #define DRIVER_NAME "mts-io" @@ -890,14 +890,6 @@ static int __init mts_io_init(void) // start the reset handler reset_callback(NULL); - if (mts_hw_version == MTP_0_0) { - /* Resetting/powering-on radio on MTP */ - log_info("Resetting/powering-on radio"); - mutex_lock(&mts_io_mutex); - radio_reset_mtp(); - mutex_unlock(&mts_io_mutex); - } - /* init timers */ setup_timer(&radio_reset_timer, radio_reset_timer_callback, 0); setup_timer(&radio_reset_available_timer, radio_reset_available_timer_callback, 0); -- cgit v1.2.3