diff options
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | io-module/machine/mtcap3.c | 540 | ||||
| -rw-r--r-- | io-module/mts-io.c | 60 | ||||
| -rw-r--r-- | io-module/mts_io_module.h | 6 | 
4 files changed, 592 insertions, 16 deletions
| diff --git a/configure.ac b/configure.ac index 2811759..fc176d5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([mts-io], [4.5.2]) +AC_INIT([mts-io], [4.6.0])  AC_CONFIG_SRCDIR([util/mts_util_lora2_reset.c])  AM_INIT_AUTOMAKE  AM_CONFIG_HEADER([config.h]) diff --git a/io-module/machine/mtcap3.c b/io-module/machine/mtcap3.c new file mode 100644 index 0000000..2304a28 --- /dev/null +++ b/io-module/machine/mtcap3.c @@ -0,0 +1,540 @@ + +#define NXP_GPIO(BANK, IO) (((( BANK - 1 ) * 32) + IO)) + +/* Used for both mtcap3 0.0 and 0.1 */ +static struct gpio_pin gpio_pins_mtcap3_0_0[] = { +	{ +		.name = "ETH_RESET", +		.pin = { +			.gpio = NXP_GPIO(1, 4), // ETH_NRST - has ext PU +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "eth-reset", +		}, +	}, +	{ +		.name = "RADIO_POWER_MONITOR", +		.pin = { +			.gpio = NXP_GPIO(4, 28), // CELL_STATUS +			.flags = GPIOF_IN, +			.label = "radio-power-monitor", +		}, +	}, +	{ +		.name = "RADIO_RESET", +		.pin = { +			.gpio = NXP_GPIO(5, 4), // CELL_RESET - has ext PD - inverted through FET +			.flags = GPIOF_OUT_INIT_LOW, +			.label = "radio-reset", +		}, +	}, +	{ +		.name = "RADIO_ONOFF", +		.pin = { +			.gpio = NXP_GPIO(5, 8), // CELL_ONOFF - has ext PD - inverted through FET +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "radio-onoff", +		}, +	}, +	{ +		.name = "RADIO_POWER", +		.pin = { +			.gpio = NXP_GPIO(5, 0), // CELL_PWR_EN - has ext PD +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "radio-power", +		}, +	}, +	{ +		.name = "DEVICE_RESET", +		.pin = { +			.gpio = NXP_GPIO(2, 13), // SWITCH_IN - has EXT PU +			.flags = GPIOF_IN, +			.label = "reset", +		}, +		.active_low = 1, +	}, +	{ +		.name = "LORA_RESET", +		.pin = { +			.gpio = NXP_GPIO(1, 5), // LORA_RST +			.flags = GPIOF_OUT_INIT_LOW, +			.label = "lora/reset", +		}, +		.capability = CAPA_LORA, +	}, +	{ +		.name = "LORA_LBT_RESET", +		.pin = { +			.gpio = NXP_GPIO(1, 27), // LORA_LBT_nRESET +			.flags = GPIOF_OUT_INIT_LOW, +			.label = "lora/lbt-reset", +		}, +		.capability = CAPA_LORA, +		.active_low = 1, +	}, +	/* LEDs */ +	{ +		.name = "STATUS_LED", // DEV_LED_GN +		.pin = { +			.gpio = NXP_GPIO(2, 15), +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "led-status", +		}, +	}, +	{ +		.name = "LED2", // LED2 is for LoRa status +		.pin = { +			.gpio = NXP_GPIO(3, 27), +			.flags = GPIOF_OUT_INIT_LOW, +			.label = "led-lora", +		}, +	}, +	{ +		.name = "LED3", // LED3 is for Cellular status (Modem can directly enable it) +		.pin = { +			.gpio = NXP_GPIO(5, 5), +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "led-cd", +		}, +        // Procesor side is hooked up to drain; module on gate +		.active_low = 1, +	}, +	{ +		.name = "LED4", // LED4 is for power status  +		.pin = { +			.gpio = NXP_GPIO(3, 28), +			.flags = GPIOF_OUT_INIT_LOW, +			.label = "led-extra", +		}, +	}, +	{ +		.name = "LORA_VCORE", // LoRa Core Voltage - comes up and goes down before vio +		.pin = { +			.gpio = NXP_GPIO(2, 12), +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "lora/vcore-enable", +		}, +	}, +	{ +		.name = "LORA_VIO", // LoRa IO Voltage; goes up and comes down after vcore  +		.pin = { +			.gpio = NXP_GPIO(2, 14), +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "lora/vio-enable", +		}, +	}, +	// NXP_GPIO(3, 28), LED_EXTRA on the Rev 0 schem., is always on power +	{ }, +}; + +// Note on EG95 reset logic: this code was adapted from radio.c in  +// RadioSupervisoryChips/STM8L101-MTQ. + +// EG95 timings +#define EG95_PWRKEY_KEEPOUT_WAIT_MS (60) +#define EG95_PWRKEY_LOW_ON_WAIT_MS (540)  // >= 500ms in datasheet +#define EG95_PWRKEY_LOW_OFF_WAIT_MS (700) // >650ms in datasheet +#define EG95_POWER_MON_ON_WAIT_S (30) +#define EG95_POWER_MON_OFF_WAIT_S (35) +#define EG95_POWER_KEEPOUT_WAIT_MS (60) +#define EG95_RESET_N_WAIT_MS (300) + +/* radio control (power/reset) for mtcap3 */ +static int radio_off_mtcap3(void) +{ +    int i = 0; +    int value = 0; +	struct gpio_pin *pwrmon_pin = gpio_pin_by_attr_name("radio-power-monitor"); +	struct gpio_pin *onoff_pin = gpio_pin_by_attr_name("radio-onoff"); +	struct gpio_pin *power_pin = gpio_pin_by_attr_name("radio-power"); +     +    if (!onoff_pin || !pwrmon_pin) { +		return -ENODEV; +	} +	 +    value = gpio_get_value(pwrmon_pin->pin.gpio); +	if(value == 0) { +		log_warning("cell radio is already off"); +		return 0; +	} + +    /* The reference manual indicates that PWRKEY is equivalent to AT+QPOWD */ + +	log_info("turning off cell radio"); + +    // Toggle PWRKEY - logic is reversed to the module through the FET +	gpio_set_value(onoff_pin->pin.gpio, 0); +    msleep(EG95_PWRKEY_KEEPOUT_WAIT_MS); +    gpio_set_value(onoff_pin->pin.gpio, 1); +    msleep(EG95_PWRKEY_LOW_OFF_WAIT_MS); +    gpio_set_value(onoff_pin->pin.gpio, 0); + +    // Wait for module to indicate status +    for(i=0; i<=EG95_POWER_MON_OFF_WAIT_S; i++) { +        value = gpio_get_value(pwrmon_pin->pin.gpio); + +        if(!value) { +            break; +        } + +        msleep(1000); +    }  +     +    // disable power to the radio; We want to do this generally for  +    // battery powered MTCAP based devices. +    gpio_set_value(power_pin->pin.gpio, 0); +    msleep(EG95_POWER_KEEPOUT_WAIT_MS); +     +    if(value != 0) { +        log_warning("cell radio was still on."); +    } else { +        log_info("cell radio has been turned off"); +    } + +	return 0; +} + +static int radio_on_mtcap3(void) +{ +    int i = 0; +    int value = 0; +	struct gpio_pin *pwrmon_pin = gpio_pin_by_attr_name("radio-power-monitor"); +	struct gpio_pin *onoff_pin = gpio_pin_by_attr_name("radio-onoff"); +	struct gpio_pin *power_pin = gpio_pin_by_attr_name("radio-power"); +	 +    if (!onoff_pin || !pwrmon_pin || !power_pin) { +		return -ENODEV; +	} + +    value = gpio_get_value(pwrmon_pin->pin.gpio); + +	if(value != 0) { +		log_warning("cell radio is already on"); +		return 0; +	} + +	log_info("turning on cell radio"); +     +    // Toggle PWRKEY - lgoic is reversed to the module through the FET +	gpio_set_value(onoff_pin->pin.gpio, 0); +    msleep(EG95_PWRKEY_KEEPOUT_WAIT_MS); + +    // Enable power to the radio +    gpio_set_value(power_pin->pin.gpio, 1); +    msleep(EG95_POWER_KEEPOUT_WAIT_MS); + +    gpio_set_value(onoff_pin->pin.gpio, 1); +    msleep(EG95_PWRKEY_LOW_ON_WAIT_MS); +     +    // Wait for module to inidcate status. +    // The spec says >= 10s, but MTQ code does 30; will be on the order of secs +    for(i=0; i<=EG95_POWER_MON_ON_WAIT_S; i++) { +        value = gpio_get_value(pwrmon_pin->pin.gpio); + +        if(value) { +            break; +        } + +        msleep(1000); +    }  +     +    // Set pwrkey high (through the FET switch);  +    // MTQ code does this after waiting for radio-power-monitor assert +    gpio_set_value(onoff_pin->pin.gpio, 0); +     +    if(value == 0) { +        log_warning("cell radio is still off."); +    } else { +        log_info("cell radio has been turned on"); +    } + +	return 0; +} + +static ssize_t mts_attr_store_radio_power_mtcap3(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; +	} +	 +    mutex_lock(&mts_io_mutex); +	if (value == 0) { +		err = radio_off_mtcap3(); +	} else if (value == 1) { +		err = radio_on_mtcap3(); +	} else { +        err = -EINVAL; +    } +	mutex_unlock(&mts_io_mutex); + +	if (err) { +		return err; +	} + +	return count; +} + +// *_radio_enable_* is here for backward compatibility +static ssize_t mts_attr_store_radio_enable_mtcap3(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +    // Included for legacy compatibilty. The 'radio-power' object controls +    // power to the module, rather than 'enable.'  The radio is always  +    // enabled, and 'radio-power' mirrors the state of the regulator enable, +    // alleviating confusion, as well as ensuring clean shut down which  +    // reduce module failures.  +	return count; +} + +static ssize_t mts_attr_show_radio_enable_mtcap3(struct device *dev, +			struct device_attribute *attr, +			char *buf) +{ +	return sprintf(buf, "%d\n", 1); +} + +static ssize_t mts_attr_store_lora_power_mtcap3(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +    int value; +	int err; +	struct gpio_pin *vcore_pin = gpio_pin_by_attr_name("lora/vcore-enable"); +	struct gpio_pin *vio_pin = gpio_pin_by_attr_name("lora/vio-enable"); +     +    if ( !vcore_pin || !vio_pin) { +		return -ENODEV; +	} + +	if (sscanf(buf, "%i", &value) != 1) { +		return -EINVAL; +	} +	 +    mutex_lock(&mts_io_mutex); +	if (value == 0) { +        gpio_set_value(vio_pin->pin.gpio, 0); +        msleep(20); +        gpio_set_value(vcore_pin->pin.gpio, 0); +        log_info("LoRa VCORE/VIO disabled"); +	} else if (value == 1) { +        gpio_set_value(vcore_pin->pin.gpio, 1); +        msleep(20); +        gpio_set_value(vio_pin->pin.gpio, 1); +        log_info("LoRa VCORE/VIO enabled"); +	} else { +        err = -EINVAL; +    } +	mutex_unlock(&mts_io_mutex); + +	if (err) { +		return err; +	} + +	return count; +} + +static ssize_t mts_attr_show_lora_power_mtcap3(struct device *dev, +			struct device_attribute *attr, +			char *buf) +{ +    int value; +	struct gpio_pin *vcore_pin = gpio_pin_by_attr_name("lora/vcore-enable"); +	struct gpio_pin *vio_pin = gpio_pin_by_attr_name("lora/vio-enable"); +     +    if ( !vcore_pin || !vio_pin) { +		return -ENODEV; +	} +     +    value = gpio_get_value(vcore_pin->pin.gpio); +    value += gpio_get_value(vio_pin->pin.gpio) * 2; + +	return sprintf(buf, "%d\n", value); +} + +static ssize_t mts_attr_store_radio_reset_mtcap3(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +    int i; +	int value; +	struct gpio_pin *pwrmon_pin = gpio_pin_by_attr_name("radio-power-monitor"); +	struct gpio_pin *reset_pin = gpio_pin_by_attr_name("radio-reset"); +	 +    if ( !pwrmon_pin || !reset_pin) { +		return -ENODEV; +	} + +	value = gpio_get_value(pwrmon_pin->pin.gpio); +	if (sscanf(buf, "%i", &value) != 1) { +		return -EINVAL; +	} + +	if (value != 0 && value != -1) { +		return -EINVAL; +	} +     +    mutex_lock(&mts_io_mutex); + +    radio_off_mtcap3(); +    radio_on_mtcap3(); + +    value = gpio_get_value(pwrmon_pin->pin.gpio); +        +    // Ensure that the module status indicates that it is up +    if(!value) { +        // Something has gone wrong +         +		log_warning("cell radio not responding. Applying hard reset."); + +        // The manual advises against doing this as it is disorderly +        // We do it here as a last resort. +        gpio_set_value(reset_pin->pin.gpio, 1); +        msleep(EG95_RESET_N_WAIT_MS); +        gpio_set_value(reset_pin->pin.gpio, 0); +     +        for(i=0; i<=EG95_POWER_MON_ON_WAIT_S; i++) { +            value = gpio_get_value(pwrmon_pin->pin.gpio); + +            if(value) { +                break; +            } + +            msleep(1000); +        }  +             +        if(value == 0) { +            log_warning("Unable to reset radio."); +        } else { +            log_info("cell radio has been reset"); +        } +    } +    else +    { +        log_info("cell radio has been reset"); +    } +	 +    mutex_unlock(&mts_io_mutex); + +	return count; +} + +static ssize_t mts_attr_show_radio_power_mtcap3(struct device *dev, +			struct device_attribute *attr, +			char *buf) +{ +	int value; +	struct gpio_pin *pwrmon_pin = gpio_pin_by_attr_name("radio-power-monitor"); +	 +    if ( !pwrmon_pin) { +		return -ENODEV; +	} + +	value = gpio_get_value(pwrmon_pin->pin.gpio); + +	return sprintf(buf, "%d\n", value); +} + +static DEVICE_ATTR_MTS(dev_attr_radio_reset_mtcap3, "radio-reset", +		mts_attr_show_gpio_pin, mts_attr_store_radio_reset_mtcap3); + +static DEVICE_ATTR_MTS(dev_attr_radio_power_mtcap3, "radio-power", +		mts_attr_show_radio_power_mtcap3, mts_attr_store_radio_power_mtcap3); + +static DEVICE_ATTR_RO_MTS(dev_attr_radio_power_monitor_mtcap3, "radio-power-monitor", +		mts_attr_show_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_eth_reset_mtcap3, "eth-reset", +		mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_led_lora_gpio_mtcap3, "led-lora", +		mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_led_extra_gpio_mtcap3, "led-extra", +		mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + +static struct attribute *mtcap3_0_0_platform_attributes[] = { +		&dev_attr_vendor_id.attr, +		&dev_attr_product_id.attr, +		&dev_attr_device_id.attr, +		&dev_attr_uuid.attr, +		&dev_attr_hw_version.attr, +		&dev_attr_imei.attr, +		&dev_attr_eth_mac.attr, +		&dev_attr_has_radio.attr, +		&dev_attr_reset.attr, +		&dev_attr_reset_monitor.attr, +		&dev_attr_reset_monitor_intervals.attr, + +		&dev_attr_eth_reset_mtcap3.attr, +		&dev_attr_led_status.attr, +		&dev_attr_led_cd_gpio.attr, +		&dev_attr_led_lora_gpio_mtcap3.attr, +		&dev_attr_led_extra_gpio_mtcap3.attr, + +		/* Set to NULL if no radio -- should be 1st radio attribute */ +		&dev_attr_radio_reset_mtcap3.attr, +		&dev_attr_radio_power_mtcap3.attr, +		&dev_attr_radio_power_monitor_mtcap3.attr, + +		&dev_attr_radio_reset_backoffs.attr, +		&dev_attr_radio_reset_backoff_index.attr, +		&dev_attr_radio_reset_backoff_seconds.attr, + +		NULL, +}; + +static int  +is_radio_power_attr_mtcap3(struct attribute *attr) +{ +    return (attr ==  &dev_attr_radio_power_mtcap3.attr); +} + +static struct attribute_group mtcap3_0_0_platform_attribute_group = { +	.attrs = mtcap3_0_0_platform_attributes +}; + +// +// on-board LORA attributes are to be stored in the lora/ sub-directory +// +// +static DEVICE_ATTR_MTS(dev_attr_lora_reset_mtcap3, "reset", +		mts_attr_show_lora_gpio_pin, mts_attr_store_lora_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_lora_lbt_reset_mtcap3, "lbt-reset", +		mts_attr_show_lora_gpio_pin, mts_attr_store_lora_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_lora_power_enable_mtcap3, "power-enable", +		mts_attr_show_lora_power_mtcap3, mts_attr_store_lora_power_mtcap3); + +static DEVICE_ATTR_RO_MTS(dev_attr_lora_eui_mtcap3, "eui", +		mts_attr_show_lora_product_info); + +static DEVICE_ATTR_RO_MTS(dev_attr_lora_product_id_mtcap3, "product-id", +		mts_attr_show_lora_product_info); + +static DEVICE_ATTR_RO_MTS(dev_attr_lora_hw_version_mtcap3, "hw-version", +		mts_attr_show_lora_product_info); + +static struct attribute *mtcap3_0_0_lora_attributes[] = { +		&dev_attr_lora_eui_mtcap3.attr, +		&dev_attr_lora_product_id_mtcap3.attr, +		&dev_attr_lora_hw_version_mtcap3.attr, +		&dev_attr_lora_reset_mtcap3.attr, +		&dev_attr_lora_lbt_reset_mtcap3.attr, +		&dev_attr_lora_power_enable_mtcap3.attr, +		NULL, +}; + +static struct attribute_group mtcap3_0_0_lora_attribute_group = { +	.attrs = mtcap3_0_0_lora_attributes +}; + +// here to maintain compatiblility +static DEVICE_ATTR_MTS(dev_attr_radio_enable_mtcap3, "radio-enable", +	mts_attr_show_radio_enable_mtcap3, mts_attr_store_radio_enable_mtcap3); + +static struct attribute *mtcap3_0_0_enable_radio_attribute[] = { +        &dev_attr_radio_enable_mtcap3.attr, +}; + diff --git a/io-module/mts-io.c b/io-module/mts-io.c index cb1c48e..e4290a6 100644 --- a/io-module/mts-io.c +++ b/io-module/mts-io.c @@ -85,7 +85,7 @@ static int mts_io_probe(struct platform_device *pdev)  {      return 0;  } -     +  static int mts_io_remove(struct platform_device *pdev)  {      return 0; @@ -672,13 +672,14 @@ static int get_radio_model_from_product_id(void) {  #include "machine/mths.c"  #include "machine/mtcpm.c"  #include "machine/mt100eocg.c" +#include "machine/mtcap3.c"  /* include capabilities sub-directory support */  #include "mts_capab.c"  struct attribute **freelater = NULL; // Storage to free when driver is unloaded. -static int  +static int  mts_id_eeprom_load(void)  {    int i, j = 0; @@ -695,7 +696,7 @@ mts_id_eeprom_load(void)    int ret;    const struct firmware* fw = NULL; -  /* Attempt to load the mts-io driver */  +  /* Attempt to load the mts-io driver */    if((ret = request_firmware_direct(&fw, "0-0056/eeprom", &mts_io_platform_device->dev)) == 0) {      if(fw->size == sizeof(id_eeprom)) {        memcpy(&id_eeprom, fw->data, sizeof(id_eeprom)); @@ -704,13 +705,13 @@ mts_id_eeprom_load(void)        log_error("Invalid platform EEPROM length (%d)", fw->size);        return -EINVAL;      } -     +      release_firmware(fw);    } else {      log_error("Unable to load EEPROM contents (%d)", ret);      return -ENODEV;    } -     +  	/* If we are an MTCPM-0.0, the base board sets the radio existance, and we always  	 * add the radio-reset, etc */  	if (strncmp(id_eeprom.hw_version,HW_VERSION_MTCPM_0_0,sizeof HW_VERSION_MTCPM_0_0) != 0) { @@ -722,7 +723,7 @@ mts_id_eeprom_load(void)              }              log_debug("mts_id_eeprom_load: noradio=%d",noradio);  	} -         +  	if (((tmp=HW_VERSION_MTCAP_0_0),(mts_hw_version=MTCAP_0_0),strncmp(id_eeprom.hw_version, tmp, strlen(tmp)) == 0) ||              ((tmp=HW_VERSION_MTCAP_0_1),(mts_hw_version=MTCAP_0_1),strncmp(id_eeprom.hw_version, tmp, strlen(tmp)) == 0) ||              ((tmp=HW_VERSION_MTCAP_0_2),(mts_hw_version=MTCAP_0_2),strncmp(id_eeprom.hw_version, tmp, strlen(tmp)) == 0) || @@ -803,6 +804,37 @@ mts_id_eeprom_load(void)  			attr_group_lora = &mtcap_0_0_lora_attribute_group;  		}  		log_info("detected board %s", tmp); +    } else if ((tmp=HW_VERSION_MTCAP3_0_0),strncmp(id_eeprom.hw_version, tmp, strlen(tmp)) == 0) { +        current_blength = attr_blength = sizeof  mtcap3_0_0_platform_attributes; +        current_blength -= sizeof(struct attribute *);  /* Length without terminating NULL */ + +        if(noradio) { +            struct attribute **ap = mtcap3_0_0_platform_attribute_group.attrs; +            while(1) { +                if(ap[j] == NULL) { +                    log_info("Did not find radio reset attribute.  Possible driver fault."); +                    break; +                } +                j++; +                if (is_radio_power_attr_mtcap3(ap[j])) { +                    log_info("Pruning radio feature from mts-io",j); +                    ap[j] = NULL; +                    current_blength = j * sizeof (ap[j]); /* Size without NULL */ +                    attr_blength += sizeof (ap[j]);  /* Size of attr array with NULL */ +                    break; +                } +            } +        } + +        if (DEVICE_CAPA(id_eeprom.capa, CAPA_LORA)) { +			attr_group_lora = &mtcap3_0_0_lora_attribute_group; +		} + +		attr_group = &mtcap3_0_0_platform_attribute_group; +		gpio_pins = gpio_pins_mtcap3_0_0; +		set_buttons(default_buttons); +		mts_hw_version = MTCAP3_0_0; +        log_info("detected board %s", HW_VERSION_MTCAP3_0_0);  	} else if (strncmp(id_eeprom.hw_version, HW_VERSION_MTRE, strlen(HW_VERSION_MTRE)) == 0) {  		attr_group = &mtre_0_0_platform_attribute_group;  		gpio_pins = gpio_pins_mtre_0_0; @@ -955,7 +987,7 @@ mts_id_eeprom_load(void)  			all_attrs[current_count] = (struct attribute *)NULL;  			mtcdt_0_1_platform_attribute_group.attrs = all_attrs;  		} -                 +  		attr_group = &mtcdt_0_1_platform_attribute_group;  		gpio_pins = gpio_pins_mtcdt_0_1;  		if (DEVICE_CAPA(id_eeprom.capa, CAPA_LORA)) { @@ -1056,7 +1088,7 @@ mts_id_eeprom_load(void)  		gpio_pins = gpio_pins_mt100eocg_0_0;  		mts_hw_version = MT100EOCG_0_0;  		set_buttons(default_buttons); -		log_info("detected board %s", HW_VERSION_MT100EOCG_0_0);		 +		log_info("detected board %s", HW_VERSION_MT100EOCG_0_0);      } else {          int i; @@ -1188,7 +1220,7 @@ static int __init mts_io_init(void)          if (ret)              printk(KERN_ERR "mts-io: probe failed: %d\n", ret);          platform_driver_unregister(&mts_io_driver); -         +  	mts_io_platform_device = platform_device_alloc(PLATFORM_NAME, -1);  	if (!mts_io_platform_device)  		return -ENOMEM; @@ -1211,7 +1243,7 @@ static int __init mts_io_init(void)  		if (ret) {  			printk(KERN_ERR "mts-io:mts-io-dout: probe failed: %d\n", ret);  		} -	}	 +	}  	if (DEVICE_CAPA(id_eeprom.capa, CAPA_DIN)) {  		ret = spi_register_driver(&mts_spi_din_driver);  		if (ret) { @@ -1250,10 +1282,10 @@ static int __init mts_io_init(void)  				log_debug("could not request pin %s (%d) but it could have already been requested under a different pin name", pin->name, ret);  		}  	} -	 +  	// Create CPU directory if approprate (only MTCDT3 for now)  	ret = mts_cpu_dir_create(mts_hw_version); -         +  	// start general buttons processing  	init_buttons(); @@ -1277,7 +1309,7 @@ static void __exit mts_io_exit(void)  {  	if (DEVICE_CAPA(id_eeprom.capa, CAPA_DOUT)) {  		spi_unregister_driver(&mts_spi_dout_driver); -	}	 +	}  	if (DEVICE_CAPA(id_eeprom.capa, CAPA_DIN)) {  		spi_unregister_driver(&mts_spi_din_driver);  	} @@ -1292,7 +1324,7 @@ static void __exit mts_io_exit(void)          for (pin = gpio_pins; *pin->name; pin++)              if (pin->capability == 0 || DEVICE_CAPA(id_eeprom.capa,pin->capability))                  gpio_free(pin->pin.gpio); -        +  	cleanup_buttons();  	//cleanup supercap monitor worker if SUPERCAP CAPA is true diff --git a/io-module/mts_io_module.h b/io-module/mts_io_module.h index 44aeade..5655f29 100644 --- a/io-module/mts_io_module.h +++ b/io-module/mts_io_module.h @@ -5,7 +5,7 @@   * MTAC cards.   */ -#define DRIVER_VERSION  "v4.5.2" +#define DRIVER_VERSION  "v4.6.0"  #define DRIVER_AUTHOR   "Multitech Systems"  #define DRIVER_DESC "MTS-IO Controller"  #define DRIVER_NAME "mts-io" @@ -44,6 +44,9 @@  #define HW_VERSION_MTHS_0_0			"MTHS-0.0"   // Never released  #define HW_VERSION_MTHS_0_1			"MTHS-0.1" +// NXP i.MX Platforms */ +#define HW_VERSION_MTCAP3_0_0			"MTCAP3-0.0" +  /* TI OMAP Platforms */  #define PRODUCT_ID_MTCPM             "MTCPM" @@ -75,6 +78,7 @@ enum {  	MTHS_0_1,  	MTCPM_0_0,  	MTCPM_0_1, +    MTCAP3_0_0,  };  /* Commented because it is not used. Сonflicts with <linux/leds.h> */ | 
