summaryrefslogtreecommitdiff
path: root/io-module
diff options
context:
space:
mode:
Diffstat (limited to 'io-module')
-rw-r--r--io-module/at91gpio.h36
-rw-r--r--io-module/buttons.h1
-rw-r--r--io-module/gpio.c16
-rw-r--r--io-module/machine/mtcdt.c290
-rw-r--r--io-module/mts-io.c66
-rw-r--r--io-module/mts_io.h1
-rw-r--r--io-module/mts_io_module.h6
-rw-r--r--io-module/radio_udev_discovery.c1
-rw-r--r--io-module/version.h9
9 files changed, 418 insertions, 8 deletions
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 <linux/leds.h> */
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 <linux/signalfd.h>
#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