From 883e395b2b07ab04f8fe57ac91e63e71dde5d4f6 Mon Sep 17 00:00:00 2001 From: John Klug Date: Tue, 10 Aug 2021 18:21:34 -0500 Subject: Add MTRE support --- io-module/machine/mtcpm.c | 4 +- io-module/machine/mtre.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++ io-module/mts-io.c | 37 ++++++ io-module/mts_eeprom.h | 7 ++ io-module/mts_io_module.h | 8 +- io-module/mts_leds.c | 146 ++++++++++++++++++++++++ 6 files changed, 480 insertions(+), 4 deletions(-) create mode 100644 io-module/machine/mtre.c create mode 100644 io-module/mts_leds.c 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 #include #include +#include #include #include @@ -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 */ +/*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++; + } +} -- cgit v1.2.3