summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Klug <john.klug@multitech.com>2021-08-10 18:21:34 -0500
committerJohn Klug <john.klug@multitech.com>2021-08-10 18:21:34 -0500
commit883e395b2b07ab04f8fe57ac91e63e71dde5d4f6 (patch)
tree0de0fda50ea07bbcbe1c255a4c94372557c5d97f
parentba8deb097645259e2760a24abc4e326f825ee609 (diff)
downloadmts-io-883e395b2b07ab04f8fe57ac91e63e71dde5d4f6.tar.gz
mts-io-883e395b2b07ab04f8fe57ac91e63e71dde5d4f6.tar.bz2
mts-io-883e395b2b07ab04f8fe57ac91e63e71dde5d4f6.zip
Add MTRE support
-rw-r--r--io-module/machine/mtcpm.c4
-rw-r--r--io-module/machine/mtre.c282
-rw-r--r--io-module/mts-io.c37
-rw-r--r--io-module/mts_eeprom.h7
-rw-r--r--io-module/mts_io_module.h8
-rw-r--r--io-module/mts_leds.c146
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++;
+ }
+}