From fdc6f30e9da19f19669ecfc6c66d02abf9057959 Mon Sep 17 00:00:00 2001 From: John Klug Date: Fri, 29 Oct 2021 10:45:43 -0500 Subject: MTCDT-0.2 with PCA9557 support --- io-module/at91gpio.h | 36 +++++ io-module/buttons.h | 1 + io-module/gpio.c | 16 ++- io-module/machine/mtcdt.c | 290 +++++++++++++++++++++++++++++++++++++++ io-module/mts-io.c | 66 +++++++++ io-module/mts_io.h | 1 + io-module/mts_io_module.h | 6 +- io-module/radio_udev_discovery.c | 1 + io-module/version.h | 9 ++ 9 files changed, 418 insertions(+), 8 deletions(-) create mode 100644 io-module/version.h diff --git a/io-module/at91gpio.h b/io-module/at91gpio.h index c2f8a77..f9b527d 100644 --- a/io-module/at91gpio.h +++ b/io-module/at91gpio.h @@ -179,4 +179,40 @@ #define AT91_PIN_PE30 (0x80 + 30) #define AT91_PIN_PE31 (0x80 + 31) +/* MTCDT-0.2 I2C I/O Port expanders + * ARCH_NR_GPIOS is set to 512 in + * gpio.h if it is not set in + * the kernel configuration with + * CONFIG_ARCH_NR_GPIO. If that number + * ever chnages, the BASE integer will + * change as well. 512 - 8 = 504 */ +#define PCA9557_0_BASE 504 // i2c address 0x18 +#define PCA9557_0_IO0 (PCA9557_0_BASE + 0) +#define PCA9557_0_IO1 (PCA9557_0_BASE + 1) +#define PCA9557_0_IO2 (PCA9557_0_BASE + 2) +#define PCA9557_0_IO3 (PCA9557_0_BASE + 3) +#define PCA9557_0_IO4 (PCA9557_0_BASE + 4) +#define PCA9557_0_IO5 (PCA9557_0_BASE + 5) +#define PCA9557_0_IO6 (PCA9557_0_BASE + 6) +#define PCA9557_0_IO7 (PCA9557_0_BASE + 7) + +/* This value depends on order of discovery. + * This controller has a higher address on + * the I2C bus and the pins are assigned + * in the order of discovery from highest + * to lowest pin numbers. + * + * GPIO numbers can be verified by + * examining /sys/kernel/debug/gpio. + */ +#define PCA9557_1_BASE 496 // i2c address 0x19 +#define PCA9557_1_IO0 (PCA9557_1_BASE + 0) +#define PCA9557_1_IO1 (PCA9557_1_BASE + 1) +#define PCA9557_1_IO2 (PCA9557_1_BASE + 2) +#define PCA9557_1_IO3 (PCA9557_1_BASE + 3) +#define PCA9557_1_IO4 (PCA9557_1_BASE + 4) +#define PCA9557_1_IO5 (PCA9557_1_BASE + 5) +#define PCA9557_1_IO6 (PCA9557_1_BASE + 6) +#define PCA9557_1_IO7 (PCA9557_1_BASE + 7) + #endif diff --git a/io-module/buttons.h b/io-module/buttons.h index ef80f34..d7ce8bd 100644 --- a/io-module/buttons.h +++ b/io-module/buttons.h @@ -34,6 +34,7 @@ #include "mts_io_module.h" #include "mts_io.h" +#include "version.h" #define BUTTON_CHECK_PER_SEC 8 #define BUTTON_INTERVAL (HZ / BUTTON_CHECK_PER_SEC) diff --git a/io-module/gpio.c b/io-module/gpio.c index 0b45300..e754ed6 100644 --- a/io-module/gpio.c +++ b/io-module/gpio.c @@ -44,6 +44,14 @@ struct gpio_pin *gpio_pin_by_attr_name(const char *name) { return NULL; } +/* Any gpio that could potentially get routed over an i2c bus + * as opposed to a memory write to a register must call + * "cansleep" versions of gpio functions. The purpose of the + * function is to remind kernel driver writers that any GPIO + * routed over i2c (or spi) cannot be accessed in an interrupt + * handler. Interrupt handlers should use the GPIO pins + * that are memory mapped. gpio_get_value and gpio_set_value + * cannot be used with the PCA 9557 or a dump will result. */ ssize_t mts_attr_show_gpio_pin(struct device *dev, struct device_attribute *attr, char *buf) @@ -57,7 +65,7 @@ ssize_t mts_attr_show_gpio_pin(struct device *dev, mutex_lock(&mts_io_mutex); - value = gpio_get_value(pin->pin.gpio); + value = gpio_get_value_cansleep(pin->pin.gpio); mutex_unlock(&mts_io_mutex); @@ -92,7 +100,7 @@ static ssize_t mts_attr_store_gpio_pin(struct device *dev, mutex_lock(&mts_io_mutex); - gpio_set_value(pin->pin.gpio, value); + gpio_set_value_cansleep(pin->pin.gpio, value); mutex_unlock(&mts_io_mutex); @@ -105,11 +113,11 @@ static int reset_gpio_pin(struct gpio_pin *pin, unsigned int delay_ms, unsigned return -ENODEV; } - gpio_set_value(pin->pin.gpio, value); + gpio_set_value_cansleep(pin->pin.gpio, value); mdelay(delay_ms); - gpio_set_value(pin->pin.gpio, !value); + gpio_set_value_cansleep(pin->pin.gpio, !value); return 0; } diff --git a/io-module/machine/mtcdt.c b/io-module/machine/mtcdt.c index b753a9e..f8b5f0b 100644 --- a/io-module/machine/mtcdt.c +++ b/io-module/machine/mtcdt.c @@ -351,6 +351,235 @@ static struct gpio_pin gpio_pins_mtcdt_0_1[] = { { }, }; +// MTCDT-0.2, Schematic Rev L dated 8 Nov 2021. +static struct gpio_pin gpio_pins_mtcdt_0_2[] = { + { + .name = "RADIO_RESET", + .pin = { + .gpio = AT91_PIN_PC3, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "radio-reset", + }, + }, + { + .name = "RADIO_RESET", + .pin = { + .gpio = AT91_PIN_PC3, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "radio-power", + }, + }, + { + .name = "RADIO_STATUS", + .pin = { + .gpio = PCA9557_0_IO2, + .flags = GPIOF_IN, + .label = "radio-status", + }, + }, + { + .name = "DEVICE_RESET", + .pin = { + .gpio = AT91_PIN_PC2, + .flags = GPIOF_IN, + .label = "reset", + }, + .active_low = 1, + }, + { + .name = "LS_LED", /* LED7 */ + .pin = { + .gpio = AT91_PIN_PA14, +#if LED_LS_CONTROLLABLE + .flags = GPIOF_OUT_INIT_HIGH, +#else + .flags = GPIOF_IN, +#endif + .label = "led-ls", + }, + .active_low = 1, + }, + { + .name = "STATUS_LED", /* LED2 */ + .pin = { + .gpio = AT91_PIN_PA24, + .flags = GPIOF_OUT_INIT_LOW, + .label = "led-status", + }, + .active_low = 1, + }, + { + .name = "LED5", + .pin = { + .gpio = PCA9557_1_IO0, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-cd", + }, + .active_low = 1, + }, + { + .name = "LED5", + .pin = { + .gpio = PCA9557_1_IO0, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-a", + }, + .active_low = 1, + }, + { + .name = "LED1", + .pin = { + .gpio = PCA9557_1_IO1, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-sig1", + }, + .active_low = 1, + }, + { + .name = "LED1", + .pin = { + .gpio = PCA9557_1_IO1, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-b", + }, + .active_low = 1, + }, + { + .name = "LED4", + .pin = { + .gpio = PCA9557_1_IO2, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-sig2", + }, + .active_low = 1, + }, + { + .name = "LED4", + .pin = { + .gpio = PCA9557_1_IO2, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-c", + }, + .active_low = 1, + }, + { + .name = "LED3", + .pin = { + .gpio = PCA9557_0_IO0, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-sig3", + }, + .active_low = 1, + }, + { + .name = "LED3", + .pin = { + .gpio = PCA9557_0_IO0, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "led-d", + }, + .active_low = 1, + }, + { + .name = "ETH_RESET", + .pin = { + .gpio = AT91_PIN_PC4, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "eth-reset", + } + }, + { + .name = "WIFI_BT_ULPWKUP", + .pin = { + .gpio = AT91_PIN_PA0, + .flags = GPIOF_IN, + .label = "wifi-bt-ulpwkup", + }, + .capability = CAPA_WIFI, + }, + { + .name = "WIFI_BT_LPWKUP", + .pin = { + .gpio = PCA9557_0_IO1, + .flags = GPIOF_IN, + .label = "wifi-bt-lpwkup", + }, + .capability = CAPA_WIFI, + }, + { + .name = "WIFI_BT_INT", + .pin = { + .gpio = AT91_PIN_PB11, + .flags = GPIOF_IN, + .label = "wifi-bt-int", + }, + .capability = CAPA_WIFI, + }, + { + .name = "WIFI_BT_RESET", + .pin = { + .gpio = AT91_PIN_PD14, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "wifi-bt-reset", + }, + .capability = CAPA_WIFI, + }, + { + .name = "GNSS_RESET", + .pin = { + .gpio = AT91_PIN_PD15, + .flags = GPIOF_OUT_INIT_LOW, /* Keep GPS quiet during boot for EXAR */ + .label = "gnss-reset", + }, + .capability = CAPA_GPS, + }, + { + .name = "SECURE_RESET", + .pin = { + .gpio = AT91_PIN_PD16, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "secure-reset", + } + }, + { + .name = "MTQ_RESET", + .pin = { + .gpio = AT91_PIN_PD17, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "mtq-reset", + } + }, + { + .name = "USBHUB_RESET", + .pin = { + .gpio = AT91_PIN_PD18, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "usbhub-reset", + } + }, + { + .name = "GNSS_INT", + .pin = { + .gpio = AT91_PIN_PD19, + .flags = GPIOF_OUT_INIT_HIGH, + .label = "gnss-int", + }, + .capability = CAPA_GPS, + }, + { + .name = "WIFI_BT_LPMODE", + .pin = { + .gpio = AT91_PIN_PD20, + .flags = GPIOF_IN, + .label = "wifi-bt-lpmode", + }, + .capability = CAPA_WIFI, + }, + { }, +}; + + + static DEVICE_ATTR_MTS(dev_attr_wifi_bt_lpwkup, "wifi-bt-lpwkup", mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); static DEVICE_ATTR_MTS(dev_attr_wifi_bt_ulpwkup, "wifi-bt-ulpwkup", @@ -373,6 +602,8 @@ static DEVICE_ATTR_RO_MTS(dev_attr_wifi_mac, "mac-wifi", mts_attr_show_product_info); static DEVICE_ATTR_RO_MTS(dev_attr_bluetooth_mac, "mac-bluetooth", mts_attr_show_product_info); +static DEVICE_ATTR_RO_MTS(dev_attr_radio_status, "radio-status", + mts_attr_show_gpio_pin); static struct attribute *mtcdt_platform_attributes[] = { &dev_attr_vendor_id.attr, @@ -456,6 +687,47 @@ static struct attribute *mtcdt_0_1_platform_attributes[] = { NULL, }; +static struct attribute *mtcdt_0_2_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_led_status.attr, + &dev_attr_led_cd_gpio.attr, + &dev_attr_led_sig1_gpio.attr, + &dev_attr_led_sig2_gpio.attr, + &dev_attr_led_sig3_gpio.attr, + + &dev_attr_led_a_gpio.attr, + &dev_attr_led_b_gpio.attr, + &dev_attr_led_c_gpio.attr, + &dev_attr_led_d_gpio.attr, + + &dev_attr_usbhub_reset.attr, + &dev_attr_eth_reset.attr, + + &dev_attr_radio_power.attr, /* Must be first radio attribute */ + &dev_attr_radio_reset.attr, + &dev_attr_radio_status.attr, + + &dev_attr_radio_reset_backoffs.attr, + &dev_attr_radio_reset_backoff_index.attr, + &dev_attr_radio_reset_backoff_seconds.attr, + + // UDEV notification of radio discovery + &dev_attr_radio_udev_discovery.attr, + &dev_attr_radio_reset_monitor.attr, + NULL, +}; + static struct attribute *mtcdt_0_1_wifi_bt_attributes[] = { &dev_attr_wifi_bt_lpwkup.attr, &dev_attr_wifi_bt_ulpwkup.attr, @@ -466,11 +738,25 @@ static struct attribute *mtcdt_0_1_wifi_bt_attributes[] = { &dev_attr_wifi_mac.attr, }; +static struct attribute *mtcdt_0_2_wifi_bt_attributes[] = { + &dev_attr_wifi_bt_lpwkup.attr, + &dev_attr_wifi_bt_ulpwkup.attr, + &dev_attr_wifi_bt_reset.attr, + &dev_attr_wifi_bt_lpmode.attr, + &dev_attr_wifi_bt_int.attr, + &dev_attr_bluetooth_mac.attr, + &dev_attr_wifi_mac.attr, +}; + static struct attribute *mtcdt_0_1_gnss_attributes[] = { &dev_attr_gnss_reset.attr, &dev_attr_gnss_int.attr, }; +static struct attribute *mtcdt_0_2_gnss_attributes[] = { + &dev_attr_gnss_reset.attr, + &dev_attr_gnss_int.attr, +}; static struct attribute_group mtcdt_platform_attribute_group = { .attrs = mtcdt_platform_attributes @@ -480,6 +766,10 @@ static struct attribute_group mtcdt_0_1_platform_attribute_group = { }; +static struct attribute_group mtcdt_0_2_platform_attribute_group = { + .attrs = mtcdt_0_2_platform_attributes +}; + static int is_radio_power_attr_mtcdt(struct attribute *attr) { diff --git a/io-module/mts-io.c b/io-module/mts-io.c index ed0cb49..8b1fbec 100644 --- a/io-module/mts-io.c +++ b/io-module/mts-io.c @@ -46,6 +46,7 @@ #include "at91gpio.h" #include "mts_io_module.h" +#include "version.h" #include "mts_io.h" #include "buttons.h" #include "mts_supercap.h" @@ -80,6 +81,13 @@ MODULE_DEVICE_TABLE(of, mts_io_dt_ids); /* on-board EEPROM */ static struct mts_id_eeprom_layout id_eeprom; +// Allow other modules to query the hardware version +const char *mts_get_hw_version(void) +{ + return id_eeprom.hw_version; +} +EXPORT_SYMBOL(mts_get_hw_version); + #include "adc.c" static int mts_io_probe(struct platform_device *pdev) @@ -544,6 +552,9 @@ static DEVICE_ATTR_MTS(dev_attr_led_d_gpio, "led-d", static DEVICE_ATTR_MTS(dev_attr_led_e_gpio, "led-e", mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); + + + /* eeprom info */ static ssize_t mts_attr_show_product_info(struct device *dev, struct device_attribute *attr, @@ -962,6 +973,61 @@ mts_id_eeprom_load(void) gpio_pins = gpio_pins_mtcdt_0_1; set_buttons(default_buttons); log_info("detected board %s", tmp); + } else if ((tmp=HW_VERSION_MTCDT_0_2),(mts_hw_version=MTCDT_0_2),strncmp(id_eeprom.hw_version, tmp, strlen(tmp)) == 0) { + need_append = 0; + current_blength = attr_blength = sizeof mtcdt_0_2_platform_attributes; + current_blength -= sizeof(struct attribute *); /* Length without terminating NULL */ + + /* See if we have no radio, and if so, prune out the stuff that follows */ + if(noradio) { + struct attribute **ap = mtcdt_0_2_platform_attribute_group.attrs; + while(1) { + if(ap[j] == NULL) { + log_info("Did not find radio power attribute. Possible driver fault."); + break; + } + j++; + if (is_radio_power_attr_mtcdt(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_WIFI)) { + attr_blength += sizeof mtcdt_0_2_wifi_bt_attributes; + need_append = 1; + } + if(DEVICE_CAPA(id_eeprom.capa, CAPA_GPS)) { + attr_blength += sizeof mtcdt_0_2_gnss_attributes; + need_append = 1; + } + if (need_append) { + freelater = all_attrs = kmalloc(attr_blength,GFP_KERNEL); + current_count = current_blength/(sizeof (struct attribute *)); + memcpy(all_attrs,mtcdt_0_2_platform_attributes,current_blength); + if(DEVICE_CAPA(id_eeprom.capa, CAPA_WIFI)) { + log_info("Adding WiFi/BT to mts-io driver"); + memcpy(all_attrs + current_count,mtcdt_0_2_wifi_bt_attributes,sizeof mtcdt_0_2_wifi_bt_attributes); + current_count += sizeof mtcdt_0_2_wifi_bt_attributes / (sizeof (struct attribute *)); + } + if(DEVICE_CAPA(id_eeprom.capa, CAPA_GPS)) { + log_info("Adding GPS to mts-io driver"); + attr_blength += sizeof mtcdt_0_2_gnss_attributes; + memcpy(all_attrs + current_count,mtcdt_0_2_gnss_attributes,sizeof mtcdt_0_2_gnss_attributes); + current_count += sizeof mtcdt_0_2_gnss_attributes / (sizeof (struct attribute *)); + } + all_attrs[current_count] = (struct attribute *)NULL; + mtcdt_0_2_platform_attribute_group.attrs = all_attrs; + } + + attr_group = &mtcdt_0_2_platform_attribute_group; + gpio_pins = gpio_pins_mtcdt_0_2; + set_buttons(default_buttons); + log_info("detected board %s", tmp); } else if ((tmp=HW_VERSION_MTCDTIPHP_0_0),strncmp(id_eeprom.hw_version, tmp, strlen(tmp)) == 0) { need_append = 0; current_blength = attr_blength = sizeof mtcdt_0_1_platform_attributes; diff --git a/io-module/mts_io.h b/io-module/mts_io.h index 2c4b7b6..4f46804 100644 --- a/io-module/mts_io.h +++ b/io-module/mts_io.h @@ -50,6 +50,7 @@ struct gpio_pin { }; extern int mts_has_radio(const char *product_id, size_t len); +extern const char *mts_get_hw_version(void); #endif /* __MTS_IO_H */ diff --git a/io-module/mts_io_module.h b/io-module/mts_io_module.h index eca15a3..4eb0ff0 100644 --- a/io-module/mts_io_module.h +++ b/io-module/mts_io_module.h @@ -5,10 +5,6 @@ * MTAC cards. */ -#define DRIVER_VERSION "v4.7.2" -#define DRIVER_AUTHOR "Multitech Systems" -#define DRIVER_DESC "MTS-IO Controller" -#define DRIVER_NAME "mts-io" #define DEBUG 0 /* Atmel AT91 Platforms */ @@ -36,6 +32,7 @@ #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_MTCDT_0_2 "MTCDT-0.2" // Atmel Serial and PCA9557 #define HW_VERSION_MTCDTIP_0_0 "MTCDTIP-0.0" #define HW_VERSION_MTCDTIPHP_0_0 "MTCDTIPHP-0.0" // Also known as LoRa 2.1 #define HW_VERSION_MTCAP_0_0 "MTCAP-0.0" @@ -81,6 +78,7 @@ enum { MTCPM_0_0, MTCPM_0_1, MTCAP3_0_0, + MTCDT_0_2, }; /* Commented because it is not used. Сonflicts with */ diff --git a/io-module/radio_udev_discovery.c b/io-module/radio_udev_discovery.c index 3a557ca..6e322b1 100644 --- a/io-module/radio_udev_discovery.c +++ b/io-module/radio_udev_discovery.c @@ -7,6 +7,7 @@ #include #endif #include "mts_io_module.h" +#include "version.h" #include "radio_udev_discovery.h" /* diff --git a/io-module/version.h b/io-module/version.h new file mode 100644 index 0000000..fff0a7a --- /dev/null +++ b/io-module/version.h @@ -0,0 +1,9 @@ +#ifndef __VERSION_H +#define __VERSION_H + +#define DRIVER_VERSION "v4.8.0" +#define DRIVER_AUTHOR "Multitech Systems" +#define DRIVER_DESC "MTS-IO Controller" +#define DRIVER_NAME "mts-io" + +#endif -- cgit v1.2.3