diff options
| -rw-r--r-- | io-module/machine/mtcpm.c | 4 | ||||
| -rw-r--r-- | io-module/machine/mtre.c | 282 | ||||
| -rw-r--r-- | io-module/mts-io.c | 37 | ||||
| -rw-r--r-- | io-module/mts_eeprom.h | 7 | ||||
| -rw-r--r-- | io-module/mts_io_module.h | 8 | ||||
| -rw-r--r-- | io-module/mts_leds.c | 146 | 
6 files changed, 480 insertions, 4 deletions
| diff --git a/io-module/machine/mtcpm.c b/io-module/machine/mtcpm.c index 481d649..8e1c3c2 100644 --- a/io-module/machine/mtcpm.c +++ b/io-module/machine/mtcpm.c @@ -65,7 +65,7 @@ static struct gpio_pin gpio_pins_mtcpm[] = {  	{  		.name = "USBHUB_RESET",  		.pin = { -            .gpio = OMAP_GPIO(2, 3), +			.gpio = OMAP_GPIO(3, 15),  			.flags = GPIOF_OUT_INIT_HIGH,  			.label = "usbhub-reset",  		}, @@ -83,7 +83,7 @@ static struct gpio_pin gpio_pins_mtcpm[] = {  	{  		.name = "GNSS_INT",  		.pin = { -            .gpio = OMAP_GPIO(2, 16),  +			.gpio = OMAP_GPIO(5,12), /* 5_12 */  			.flags = GPIOF_OUT_INIT_HIGH,  			.label = "gnss-int",  		}, diff --git a/io-module/machine/mtre.c b/io-module/machine/mtre.c new file mode 100644 index 0000000..e3df31c --- /dev/null +++ b/io-module/machine/mtre.c @@ -0,0 +1,282 @@ +static struct gpio_pin gpio_pins_mtre_0_0[] = { +	{ +		.name = "ETH_RESET", +		.pin = { +			.gpio = AT91_PIN_PC6, +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "eth-reset", +		}, +		.active_low = 0, +	}, +	{ +		.name = "RADIO_RESET", +		.pin = { +			.gpio = AT91_PIN_PC3, +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "radio-reset", +		}, +		.active_low = 0, +	}, +	{ +		.name = "RADIO_POWER", +		.pin = { +			.gpio = AT91_PIN_PC3, +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "radio-power", +		}, +		.active_low = 0, +	}, +	{ +		.name = "DEVICE_RESET", +		.pin = { +			.gpio = AT91_PIN_PC4, +			.flags = GPIOF_IN, +			.label = "reset", +		}, +		.active_low = 1, +	}, +	{ +		.name = "RI_B", +		.pin = { +			.gpio = AT91_PIN_PC25, +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "extserial-ri", +		}, +		.active_low = 1, +	}, +	{ +		.name = "DTR_B", +		.pin = { +			.gpio = AT91_PIN_PC26, +			.flags = GPIOF_IN, +			.label = "extserial-dtr", +		}, +		.active_low = 1, +	}, +	{ +		.name = "DSR_B", +		.pin = { +			.gpio = AT91_PIN_PC27, +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "extserial-dsr", +		}, +		.active_low = 1, +	}, +	{ +		.name = "DCD_B", +		.pin = { +			.gpio = AT91_PIN_PC28, +			.flags = GPIOF_OUT_INIT_HIGH, +			.label = "extserial-dcd", +		}, +		.active_low = 1, +	}, +	{ }, +}; + +static +struct mts_led mtre_0_0_leds[] = { +	{.label = "led-cd",},                   /* (cellular) Link Status */ +	{.label = "led-sig1",},                 /* (cellular) Link Quality */ +	{.label = "led-sig2",},                 /* (cellular) Link Quality */ +	{.label = "led-sig3",},                 /* (cellular) Link Quality */ +	{.label = "led-sig4",},                 /* (cellular) Link Quality */ +	{.label = "led-alarm",},                /* Alarm */ +	{.label = "led-no-alarm",},             /* Enabled (out-of-phase with Alarm) */ +	{} +}; + +/* Initial state of ALARM is "no alarm" = 0, "major alarm" state is 1 */ +/* alarm_mtre value represents alarm state and controls both ALARM and NO-ALARM LEDs */ +static int alarm_mtre = 0; + +/* Initial state of DEVICE_READY is "not ready", "ready" state is 1 */ +/* If device_ready_mtre is 0 than NO-ALARM (marked ENABLED on the front panel) LED should be turned off */ +static int device_ready_mtre = 0; + +static unsigned long delay_on_alarm_mtre = 1000; +static unsigned long delay_off_alarm_mtre = 1; +static unsigned long delay_on_no_alarm_mtre = 1000; +static unsigned long delay_off_no_alarm_mtre = 1; + +static +void mts_update_alarm_mtre(int value) +{ +	const struct mts_led *led_alarm = mts_led_by_label("led-alarm"); +	const struct mts_led *led_no_alarm = mts_led_by_label("led-no-alarm"); + +	if (!led_alarm || !led_no_alarm) { +		return; +	} + +	if (value > 2) { +		/* just update the LEDs with current state */ +		value = alarm_mtre; +	} + +	if (value == 0) { +		/* NO ALARM */ +		alarm_mtre = 0; +		mts_led_set(led_alarm, 1);      /* turn ALARM LED off (note: inverted pin) */ +		mts_led_set(led_no_alarm, device_ready_mtre); /* turn on NO-ALARM only if "device ready" */ +	} +	else if (value == 1) { +		/* ALARM */ +		alarm_mtre = 1; +		mts_led_set(led_alarm, 0);      /* turn ALARM LED on (note: inverted pin) */ +		mts_led_set(led_no_alarm, 0);   /* turn off NO-ALARM */ +	} +	else if (value == 2 && alarm_mtre != 1) { +		/* Minor ALARM: blink for 1 second if there is no "major alarm" */ +		delay_on_alarm_mtre = 1; +		delay_off_alarm_mtre = 1000; +		mts_led_blink(led_alarm, &delay_on_alarm_mtre, &delay_off_alarm_mtre, 1); /* blink ALARM LED (note: inverted) */ + +		if (device_ready_mtre) { +			/* blink NO-ALARM only if "device ready" */ +			delay_on_no_alarm_mtre = 1; +			delay_off_no_alarm_mtre = 1000; +			mts_led_blink(led_no_alarm, &delay_on_no_alarm_mtre, &delay_off_no_alarm_mtre, 1); +		} +	} +} + +static +ssize_t mts_attr_store_alarm_mtre(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +	int value; + +	if (sscanf(buf, "%i", &value) != 1) { +		return -EINVAL; +	} + +	mts_update_alarm_mtre(value); + +	return count; +} + +static +ssize_t mts_attr_show_alarm_mtre(struct device *dev, +		struct device_attribute *attr, char *buf) +{ +	return sprintf(buf, "%d\n", alarm_mtre); +} + +static +ssize_t mts_attr_store_device_ready_mtre(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +	int value; + +	if (sscanf(buf, "%i", &value) != 1) { +		return -EINVAL; +	} + +	if (value == 0) { +		device_ready_mtre = 0; +	} +	else if (value == 1) { +		device_ready_mtre = 1; +	} +	else { +		return -EINVAL; +	} + +	/* just update the LEDs with current state */ +	mts_update_alarm_mtre(100); + +	return count; +} + +static +ssize_t mts_attr_show_device_ready_mtre(struct device *dev, +		struct device_attribute *attr, char *buf) +{ +	return sprintf(buf, "%d\n", device_ready_mtre); +} + +static DEVICE_ATTR_MTS(dev_attr_eth_reset_mtre, "eth-reset", +	mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_extserial_ri_gpio_mtre, "extserial-ri", +	mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + +static DEVICE_ATTR_RO_MTS(dev_attr_extserial_dtr_gpio_mtre, "extserial-dtr", +	mts_attr_show_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_extserial_dsr_gpio_mtre, "extserial-dsr", +	mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_extserial_dcd_gpio_mtre, "extserial-dcd", +	mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + +static DEVICE_ATTR_MTS(dev_attr_alarm_mtre, "alarm", +	mts_attr_show_alarm_mtre, mts_attr_store_alarm_mtre); + +static DEVICE_ATTR_MTS(dev_attr_device_ready_mtre, "device-ready", +	mts_attr_show_device_ready_mtre, mts_attr_store_device_ready_mtre); + +static DEVICE_ATTR_MTS(dev_attr_led_cd_i2c_mtre, "led-cd", +	mts_attr_show_led, mts_attr_store_led); + +static DEVICE_ATTR_MTS(dev_attr_led_sig1_i2c_mtre, "led-sig1", +	mts_attr_show_led, mts_attr_store_led); + +static DEVICE_ATTR_MTS(dev_attr_led_sig2_i2c_mtre, "led-sig2", +	mts_attr_show_led, mts_attr_store_led); + +static DEVICE_ATTR_MTS(dev_attr_led_sig3_i2c_mtre, "led-sig3", +	mts_attr_show_led, mts_attr_store_led); + +static DEVICE_ATTR_MTS(dev_attr_led_sig4_i2c_mtre, "led-sig4", +	mts_attr_show_led, mts_attr_store_led); + +static struct attribute *mtre_0_0_platform_attributes[] = { +	/* Common entries */ +	&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_radio_power.attr, +	&dev_attr_radio_reset.attr, + +	&dev_attr_radio_reset_backoffs.attr, +	&dev_attr_radio_reset_backoff_index.attr, +	&dev_attr_radio_reset_backoff_seconds.attr, + +	&dev_attr_extserial_ri_gpio_mtre.attr, +	&dev_attr_extserial_dtr_gpio_mtre.attr, +	&dev_attr_extserial_dsr_gpio_mtre.attr, +	&dev_attr_extserial_dcd_gpio_mtre.attr, + +	&dev_attr_eth_reset_mtre.attr, + +	&dev_attr_alarm_mtre.attr,                 /* Alarm attribute (driver for ENABLED/ALARM LEDs) */ +	&dev_attr_device_ready_mtre.attr,          /* Set device readyness attribute (affects ENABLED/ALARM LEDs) */ + +	&dev_attr_led_cd_i2c_mtre.attr,            /* (cellular) Link Status */ +	&dev_attr_led_sig1_i2c_mtre.attr,          /* (cellular) Link Quality */ +	&dev_attr_led_sig2_i2c_mtre.attr,          /* (cellular) Link Quality */ +	&dev_attr_led_sig3_i2c_mtre.attr,          /* (cellular) Link Quality */ +	&dev_attr_led_sig4_i2c_mtre.attr,          /* (cellular) Link Quality */ +#ifdef MTRE +	&dev_attr_oem_string1.attr, +	&dev_attr_oem_string2.attr, +#endif + +	NULL, +}; + + +static struct attribute_group mtre_0_0_platform_attribute_group = { +	.attrs = mtre_0_0_platform_attributes +}; diff --git a/io-module/mts-io.c b/io-module/mts-io.c index a20cd39..cb1c48e 100644 --- a/io-module/mts-io.c +++ b/io-module/mts-io.c @@ -40,6 +40,7 @@  #include <linux/kmod.h>  #include <linux/ctype.h>  #include <linux/io.h> +#include <linux/leds.h>  #include <linux/module.h>  #include <linux/firmware.h> @@ -608,6 +609,12 @@ static ssize_t mts_attr_show_product_info(struct device *dev,  			id_eeprom.lora_eui[5],  			id_eeprom.lora_eui[6],  			id_eeprom.lora_eui[7]); +#ifdef MTRE +	} else if (strcmp(attr->attr.name, "oem-string1") == 0) { +		value = sprintf(buf, "%.32s\n", id_eeprom.oem_string1); +	} else if (strcmp(attr->attr.name, "oem-string2") == 0) { +		value = sprintf(buf, "%.32s\n", id_eeprom.oem_string2); +#endif  	}  	else {  		log_error("attribute '%s' not found", attr->attr.name); @@ -633,6 +640,12 @@ static DEVICE_ATTR_RO_MTS(dev_attr_imei, "imei",  	mts_attr_show_product_info);  static DEVICE_ATTR_RO_MTS(dev_attr_eth_mac, "mac-eth",  	mts_attr_show_product_info); +#ifdef MTRE +static DEVICE_ATTR_RO_MTS(dev_attr_oem_string1, "oem-string1", +	mts_attr_show_product_info); +static DEVICE_ATTR_RO_MTS(dev_attr_oem_string2, "oem-string2", +	mts_attr_show_product_info); +#endif  static int get_radio_model_from_product_id(void) {  	int rc = RADIO_UNKNOWN; @@ -648,10 +661,14 @@ static int get_radio_model_from_product_id(void) {  /* include on-board lora peripheral */  #include "mts_lora.c" +/* interface to Linux /sys/class/leds/ devices */ +#include "mts_leds.c" +  /* include per-device pins and attributes */  #include "machine/mtcdt.c"  #include "machine/mtcap.c"  #include "machine/mtr.c" +#include "machine/mtre.c"  #include "machine/mths.c"  #include "machine/mtcpm.c"  #include "machine/mt100eocg.c" @@ -786,6 +803,13 @@ mts_id_eeprom_load(void)  			attr_group_lora = &mtcap_0_0_lora_attribute_group;  		}  		log_info("detected board %s", tmp); +	} 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; +		set_buttons(default_buttons); +		mts_leds = mtre_0_0_leds; +		mts_hw_version = MTRE_0_0; +		log_info("detected board %s", HW_VERSION_MTRE);  	} else if (strncmp(id_eeprom.hw_version, HW_VERSION_MTR_0_0, strlen(HW_VERSION_MTR_0_0)) == 0) {  		attr_group = &mtr_platform_attribute_group;  		gpio_pins = gpio_pins_mtr_0_0; @@ -1122,6 +1146,10 @@ mts_id_eeprom_load(void)  		log_info("lora-product-id: %.32s",  id_eeprom.lora_product_id);  		log_info("lora-hw-version: %.32s", id_eeprom.lora_hw_version);  	} +#ifdef MTRE +        log_info("oem-string1: %.32s",  id_eeprom.oem_string1); +        log_info("oem-string2: %.32s",  id_eeprom.oem_string2); +#endif  	return 0;  } @@ -1199,6 +1227,10 @@ static int __init mts_io_init(void)  		mts_load_lora_port();  	} +	if (mts_leds) { +		mts_leds_register(); +	} +  	ret = mts_capab_dir_create(mts_hw_version);  	if (ret) {  		cleanup(); @@ -1269,6 +1301,11 @@ static void __exit mts_io_exit(void)  	}  	cleanup(); + +	if (mts_leds) { +		mts_leds_unregister(); +	} +  	if (DEVICE_CAPA(id_eeprom.capa, CAPA_LORA) && attr_group_lora) {  		mts_teardown_lora_port();  	} diff --git a/io-module/mts_eeprom.h b/io-module/mts_eeprom.h index 4a003a4..2a86ebd 100644 --- a/io-module/mts_eeprom.h +++ b/io-module/mts_eeprom.h @@ -27,8 +27,15 @@ struct mts_id_eeprom_layout {  	uint8_t lora_eui[8];  	char lora_product_id[32];  	char lora_hw_version[32]; +#ifdef MTRE +	char oem_string1[32]; +	char oem_string2[32]; +	uint16_t eeprom_layout_version; +	uint8_t reserved[148]; +#else  	uint16_t eeprom_layout_version;  	uint8_t reserved[212]; +#endif  };  /* accessory card EEPROM */ diff --git a/io-module/mts_io_module.h b/io-module/mts_io_module.h index 7f12a32..44aeade 100644 --- a/io-module/mts_io_module.h +++ b/io-module/mts_io_module.h @@ -15,6 +15,7 @@  #define PRODUCT_ID_MTCDP_E1_DK			"MTCDP-E1-DK"  #define PRODUCT_ID_MT100EOCG			"MT100EOCG"  #define PRODUCT_ID_MTR				"MTR" +#define PRODUCT_ID_MTRE				"MTRE"  #define PRODUCT_ID_MTCDT			"MTCDT"  #define PRODUCT_ID_MTCAP                        "MTCAP"  #define PRODUCT_ID_MTCDTIP                      "MTCDTIP" @@ -31,6 +32,7 @@  #define HW_VERSION_MTRV1_0_1			"MTRV1-0.1"  #define HW_VERSION_MTRV1_0_2			"MTRV1-0.2"  // Cat M  #define HW_VERSION_MTRV1_0_3                    "MTRV1-0.3"  // MTR-MTQ +#define HW_VERSION_MTRE				"MTRE-0.0"  #define HW_VERSION_MTCDT_0_0			"MTCDT-0.0"  // No GPS or WiFi Capability  #define HW_VERSION_MTCDT_0_1			"MTCDT-0.1"  // Conduit refresh with GPS and WiFi possible  #define HW_VERSION_MTCDTIP_0_0			"MTCDTIP-0.0" @@ -60,6 +62,7 @@ enum {  	MTRV1_0_1,  	MTRV1_0_2,  	MTRV1_0_3, +	MTRE_0_0,  	MTCDT_0_0,  	MTCDT_0_1,  	MTCDTIP_0_0, @@ -74,11 +77,12 @@ enum {  	MTCPM_0_1,  }; -enum { +/* Commented because it is not used. Сonflicts with <linux/leds.h> */ +/*enum {  	LED_OFF,  	LED_ON,  	LED_FLASHING, -}; +};*/  enum {  	RADIO_UNKNOWN, diff --git a/io-module/mts_leds.c b/io-module/mts_leds.c new file mode 100644 index 0000000..a5cfbbb --- /dev/null +++ b/io-module/mts_leds.c @@ -0,0 +1,146 @@ +/* + * Use the code below to control the brightness of the LEDs using + * Linux LED framework instead of manipulating gpio pins or i2c registers + * directly in the mts-io module. + * + * Usage: + * + * # associate a mts-io sysfs entry with the specific LEDs + * echo led-sig1 > /sys/class/leds/pca955x:0/trigger + * echo led-sig2 > /sys/class/leds/pca955x:1/trigger + * echo led-sig3 > /sys/class/leds/pca955x:2/trigger + * + * # change the brightness + * echo 1 > /sys/device/platform/mts-io/led-sig1 + * echo 1 > /sys/device/platform/mts-io/led-sig2 + * + */ + +struct mts_led { +	const char label[32];          /* led name exposed by the mts-io kernel module */ +	struct led_trigger *trigger;   /* linux led trigger */ +}; + +static struct mts_led *mts_leds = NULL; + +/* + * Find a LED descriptor in mts_leds array by label name + */ +static +struct mts_led *mts_led_by_label(const char *label) +{ +	struct mts_led *led = mts_leds; + +	while (led && *led->label) { +		if (strcmp(led->label, label) == 0) { +			return led; +		} +		led++; +	} + +	log_error("led with %s label is not found", label); + +	return NULL; +} + +/* + * Change brightness for Linux LEDs devices + */ +static +void mts_led_set(const struct mts_led *led, int value) +{ +	enum led_brightness brightness = LED_OFF; + +	if (value != 0) brightness = LED_FULL; + +	if (led->trigger) { +		led_trigger_event(led->trigger, brightness); +	} + +	/* +	 * Note: there are also led_trigger_blink and led_trigger_blink_oneshot +	 *       functions which can potentially be used +	 */ +} + +/* + * Blink one shot + */ +static +void mts_led_blink(const struct mts_led *led, +                   unsigned long *delay_on, unsigned long *delay_off,  int invert) +{ +	if (led->trigger) { +		 led_trigger_blink_oneshot(led->trigger, delay_on, delay_off, invert); +	} +} + + +/* + * Use the function to get current LED brightness for sysfs entry + */ +static +ssize_t mts_attr_show_led(struct device *dev, +		struct device_attribute *attr, char *buf) +{ +	return sprintf(buf, "%d\n", 0); +} + +/* + * Use the function to set LED brightness from sysfs entry + */ +static +ssize_t mts_attr_store_led(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +	int value; + +	const struct mts_led *led = mts_led_by_label(attr->attr.name); + +	if (!led) { +		return -ENODEV; +	} + +	if (sscanf(buf, "%i", &value) != 1) { +		return -EINVAL; +	} + +	mts_led_set(led, value); + +	return count; +} + +/* + * Register a LED trigger for each LED declared in the mts_leds array + * Use in mts-io startup code. + */ +static +void mts_leds_register(void) +{ +	struct mts_led *led = mts_leds; + +	while (led && *led->label) { +		log_info("Registering %s led trigger", led->label); +		led_trigger_register_simple(led->label, &led->trigger); +		led++; +	} +} + +/* + * Unregister all registered LED triggers. + * Use in mts-io cleanup code. + */ +static +void mts_leds_unregister(void) +{ +	struct mts_led *led = mts_leds; + +	while (led && *led->label) { +		log_info("Unregistering %s led trigger", led->label); +		if (led->trigger) { +			led_trigger_unregister_simple(led->trigger); +			led->trigger = NULL; +		} +		led++; +	} +} | 
