summaryrefslogtreecommitdiff
path: root/io-module/mtac_gpiob.c
diff options
context:
space:
mode:
authorMike Fiore <mfiore@multitech.com>2014-09-23 10:35:11 -0500
committerMike Fiore <mfiore@multitech.com>2014-09-23 10:35:11 -0500
commita21c24fa2486e4d4a3b25d0dcbf873ae62fdbcec (patch)
tree6d78da220c6235cd33408acbd22adf9b4038bbc1 /io-module/mtac_gpiob.c
parent24c012065ca7a764e1e51a9cfc4422d649cd2851 (diff)
downloadmts-io-a21c24fa2486e4d4a3b25d0dcbf873ae62fdbcec.tar.gz
mts-io-a21c24fa2486e4d4a3b25d0dcbf873ae62fdbcec.tar.bz2
mts-io-a21c24fa2486e4d4a3b25d0dcbf873ae62fdbcec.zip
mts-io: clean up accessory card support
use custom kernel config option MTS_NUM_ACCESSORY_PORTS to find out how many slots exist (mostly) dynamically handle any number of accessory cards streamline code to make it easier to add accessory cards in the future
Diffstat (limited to 'io-module/mtac_gpiob.c')
-rw-r--r--io-module/mtac_gpiob.c552
1 files changed, 333 insertions, 219 deletions
diff --git a/io-module/mtac_gpiob.c b/io-module/mtac_gpiob.c
index 5a592b7..728634d 100644
--- a/io-module/mtac_gpiob.c
+++ b/io-module/mtac_gpiob.c
@@ -1,22 +1,130 @@
+struct spi_device *gpiob_spi[NUM_AP][3];
+struct spi_driver gpiob_spi_drivers[NUM_AP][3];
+
+static u8 spi_ap_dout_value;
+static DEFINE_MUTEX(spi_ap_dout_mutex);
+static unsigned int ap_dout_max_speed_hz = 1 * 1000 * 1000;
+module_param(ap_dout_max_speed_hz, uint, S_IRUGO);
+MODULE_PARM_DESC(
+ ap_dout_max_speed_hz,
+ "Maximum clock rate to be used with this device (default: 1 MHz)"
+);
+
+static unsigned int ap_din_max_speed_hz = 1 * 1000 * 1000;
+module_param(ap_din_max_speed_hz, uint, S_IRUGO);
+MODULE_PARM_DESC(
+ ap_din_max_speed_hz,
+ "Maximum clock rate to be used with this device (default: 1 MHz)"
+);
+
+static unsigned int ap_adc_max_speed_hz = 20 * 1000 * 1000;
+module_param(ap_adc_max_speed_hz, uint, S_IRUGO);
+MODULE_PARM_DESC(
+ ap_adc_max_speed_hz,
+ "Maximum clock rate to be used with this device (default: 20 MHz)"
+);
+
+static bool gpiob_get_dev_info_from_modalias(const char* modalias, int* port, char* buf) {
+ sscanf(modalias, "mts-io-ap%d-%s", port, buf);
+
+ return true;
+}
+
+static int mts_spi_ap_probe(struct spi_device *spi)
+{
+ int tmp;
+ int port;
+ int port_index;
+ char buf[16];
+ enum spi_devices dev;
+
+ gpiob_get_dev_info_from_modalias(spi->modalias, &port, buf);
+ port_index = port - 1;
+ if (port < 1 || port > NUM_AP) {
+ log_error("port [%d] is invalid", port);
+ return -ENODEV;
+ }
+
+ if (strstr(buf, "dout")) {
+ dev = dout;
+ spi->max_speed_hz = ap_dout_max_speed_hz;
+ spi->mode = 0;
+ } else if (strstr(buf, "din")) {
+ dev = din;
+ spi->max_speed_hz = ap_din_max_speed_hz;
+ spi->mode = SPI_CPOL;
+ } else if (strstr(buf, "adc")) {
+ dev = adc;
+ spi->max_speed_hz = ap_adc_max_speed_hz;
+ spi->mode = 0;
+ } else {
+ log_error("unknown gpiob spi device type [%s]", buf);
+ return -ENODEV;
+ }
+
+ gpiob_spi[port_index][dev] = spi;
+
+ tmp = spi_setup(gpiob_spi[port_index][dev]);
+ if (tmp < 0) {
+ log_error("spi_setup ap %d %s failed", port, buf);
+ return tmp;
+ }
+
+ if (dev == dout) {
+ spi_ap_dout_value = 0x00;
+ spi_writen(gpiob_spi[port_index][dev], &spi_ap_dout_value, 1);
+ }
+
+ return 0;
+}
+
+static int mts_spi_ap_remove(struct spi_device *spi)
+{
+ int port;
+ int port_index;
+ char buf[16];
+
+ gpiob_get_dev_info_from_modalias(spi->modalias, &port, buf);
+ port_index = port - 1;
+ if (port < 1 || port > NUM_AP) {
+ log_error("port [%d] is invalid", port);
+ return -ENODEV;
+ }
+
+ if (strstr(buf, "dout")) {
+ gpiob_spi[port_index][dout] = NULL;
+ } else if (strstr(buf, "din")) {
+ gpiob_spi[port_index][din] = NULL;
+ } else if (strstr(buf, "adc")) {
+ gpiob_spi[port_index][adc] = NULL;
+ } else {
+ log_error("unknown gpiob spi device type [%s]", buf);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+// Is there a way to make this dynamic as well?
struct gpio_pin *ap_gpio_pin_by_attr_name(const char *name) {
struct gpio_pin *pin;
char *pin_attr_name;
- if (!strcmp(name, "ap1-led1")) {
+ if (!strcmp(name, "ap-led1:1")) {
pin_attr_name = "ap1-gpio3";
- } else if (!strcmp(name, "ap1-led2")) {
+ } else if (!strcmp(name, "ap-led2:1")) {
pin_attr_name = "ap1-gpio4";
- } else if (!strcmp(name, "ap1-dout-enable")) {
+ } else if (!strcmp(name, "ap-dout-enable:1")) {
pin_attr_name = "ap1-gpio1";
- } else if (!strcmp(name, "ap1-reset")) {
+ } else if (!strcmp(name, "ap-reset:1")) {
pin_attr_name = "ap1-reset";
- } else if (!strcmp(name, "ap2-led1")) {
+ } else if (!strcmp(name, "ap-led1:2")) {
pin_attr_name = "ap2-gpio3";
- } else if (!strcmp(name, "ap2-led2")) {
+ } else if (!strcmp(name, "ap-led2:2")) {
pin_attr_name = "ap2-gpio4";
- } else if (!strcmp(name, "ap2-dout-enable")) {
+ } else if (!strcmp(name, "ap-dout-enable:2")) {
pin_attr_name = "ap2-gpio1";
- } else if (!strcmp(name, "ap2-reset")) {
+ } else if (!strcmp(name, "ap-reset:2")) {
pin_attr_name = "ap2-reset";
} else {
log_error("accessory card attribute %s not available", name);
@@ -35,8 +143,8 @@ struct gpio_pin *ap_gpio_pin_by_attr_name(const char *name) {
}
-static ssize_t mts_attr_show_ap_gpio_pin(struct device *dev,
- struct device_attribute *attr,
+static ssize_t mts_attr_show_ap_gpio_pin(struct kobject *kobj,
+ struct kobj_attribute *attr,
char *buf)
{
int value;
@@ -63,8 +171,8 @@ static ssize_t mts_attr_show_ap_gpio_pin(struct device *dev,
return sprintf(buf, "%d\n", value);
}
-static ssize_t mts_attr_store_ap_gpio_pin(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t mts_attr_store_ap_gpio_pin(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
{
int value;
struct gpio_pin *pin = ap_gpio_pin_by_attr_name(attr->attr.name);
@@ -90,46 +198,29 @@ static ssize_t mts_attr_store_ap_gpio_pin(struct device *dev,
return count;
}
-static ssize_t mts_attr_show_ap_din(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t mts_attr_show_ap_din(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int tmp;
+ int channel;
+ int port;
+ int port_index;
u8 bit;
u8 byte;
- struct spi_device* spi_dev;
- if (strstr(attr->attr.name, ":0")) {
- if (!spi_ap1_din_dev) {
- log_error("accessory card 1 din device not present");
- return -ENODEV;
- }
-
- spi_dev = spi_ap1_din_dev;
- } else if (strstr(attr->attr.name, ":1")) {
- if (!spi_ap2_din_dev) {
- log_error("accessory card 2 din device not present");
- return -ENODEV;
- }
-
- spi_dev = spi_ap2_din_dev;
- } else {
- log_error("unknown din device %s", attr->attr.name);
- return -ENODEV;
+ sscanf(attr->attr.name, "din%d:%d", &channel, &port);
+ port_index = port - 1;
+ if (channel < 0 || channel > 3) {
+ log_error("channel [%d] is invalid", channel);
+ return -ENOENT;
}
-
- if (strstr(attr->attr.name, "din0")) {
- bit = BIT(0);
- } else if (strstr(attr->attr.name, "din1")) {
- bit = BIT(1);
- } else if (strstr(attr->attr.name, "din2")) {
- bit = BIT(2);
- } else if (strstr(attr->attr.name, "din3")) {
- bit = BIT(3);
- } else {
- log_error("accessory card din attr does not exist");
+ if (port < 1 || port > NUM_AP) {
+ log_error("port [%d] is invalid", port);
return -ENOENT;
}
- tmp = spi_readn(spi_dev, &byte, 1);
+ bit = BIT(channel);
+
+ tmp = spi_readn(gpiob_spi[port_index][din], &byte, 1);
if (tmp) {
log_error("spi_read failed %d", tmp);
return tmp;
@@ -140,46 +231,29 @@ static ssize_t mts_attr_show_ap_din(struct device *dev, struct device_attribute
return sprintf(buf, "%d\n", tmp);
}
-static ssize_t mts_attr_store_ap_dout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t mts_attr_store_ap_dout(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int value;
+ int channel;
+ int port;
+ int port_index;
u8 bit;
- struct spi_device* spi_dev;
-
- if (strstr(attr->attr.name, ":0")) {
- if (!spi_ap1_dout_dev) {
- log_error("accessory card 1 dout device not present");
- return -ENODEV;
- }
- spi_dev = spi_ap1_dout_dev;
- } else if (strstr(attr->attr.name, ":1")) {
- if (!spi_ap2_dout_dev) {
- log_error("accessory card 2 dout device not present");
- return -ENODEV;
- }
-
- spi_dev = spi_ap2_dout_dev;
- } else {
- log_error("unknown dout device %s", attr->attr.name);
- return -ENODEV;
+ sscanf(attr->attr.name, "dout%d:%d", &channel, &port);
+ port_index = port - 1;
+ if (channel < 0 || channel > 3) {
+ log_error("channel [%d] is invalid", channel);
+ return -ENOENT;
}
-
- if (strstr(attr->attr.name, "dout0")) {
- bit = BIT(0);
- } else if (strstr(attr->attr.name, "dout1")) {
- bit = BIT(1);
- } else if (strstr(attr->attr.name, "dout2")) {
- bit = BIT(2);
- } else if (strstr(attr->attr.name, "dout3")) {
- bit = BIT(3);
- } else {
- log_error("accessory card dout attr does not exist");
+ if (port < 1 || port > NUM_AP) {
+ log_error("port [%d] is invalid", port);
return -ENOENT;
}
+ bit = BIT(channel);
+
if (sscanf(buf, "%i", &value) != 1) {
- log_error("accessory card dout attr invalid argument");
+ log_error("accessory card dout attr invalid argument [%d]", value);
return -EINVAL;
}
@@ -191,51 +265,32 @@ static ssize_t mts_attr_store_ap_dout(struct device *dev, struct device_attribut
spi_ap_dout_value |= bit;
}
- spi_writen(spi_dev, &spi_ap_dout_value, 1);
+ spi_writen(gpiob_spi[port_index][dout], &spi_ap_dout_value, 1);
mutex_unlock(&spi_ap_dout_mutex);
return count;
}
-static ssize_t mts_attr_show_ap_dout(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t mts_attr_show_ap_dout(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int value;
+ int channel;
+ int port;
u8 bit;
- struct spi_device* spi_dev;
- if (strstr(attr->attr.name, ":0")) {
- if (!spi_ap1_dout_dev) {
- log_error("accessory card 1 dout device not present");
- return -ENODEV;
- }
-
- spi_dev = spi_ap1_dout_dev;
- } else if (strstr(attr->attr.name, ":1")) {
- if (!spi_ap2_dout_dev) {
- log_error("accessory card 2 dout device not present");
- return -ENODEV;
- }
-
- spi_dev = spi_ap2_dout_dev;
- } else {
- log_error("unknown dout device %s", attr->attr.name);
- return -ENODEV;
+ sscanf(attr->attr.name, "dout%d:%d", &channel, &port);
+ if (channel < 0 || channel > 3) {
+ log_error("channel [%d] is invalid", channel);
+ return -ENOENT;
}
-
- if (strstr(attr->attr.name, "dout0")) {
- bit = BIT(0);
- } else if (strstr(attr->attr.name, "dout1")) {
- bit = BIT(1);
- } else if (strstr(attr->attr.name, "dout2")) {
- bit = BIT(2);
- } else if (strstr(attr->attr.name, "dout3")) {
- bit = BIT(3);
- } else {
- log_error("accessory card dout attr does not exist");
+ if (port < 1 || port > NUM_AP) {
+ log_error("port [%d] is invalid", port);
return -ENOENT;
}
+ bit = BIT(channel);
+
mutex_lock(&spi_ap_dout_mutex);
value = spi_ap_dout_value & bit ? 0 : 1;
@@ -245,48 +300,30 @@ static ssize_t mts_attr_show_ap_dout(struct device *dev, struct device_attribute
return sprintf(buf, "%d\n", value);
}
-static ssize_t mts_attr_show_ap_adc(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t mts_attr_show_ap_adc(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int tmp;
int tx_data;
int rx_data;
int channel;
+ int port;
+ int port_index;
int channel_mask = 0x0180; /* 0b 0000 0001 1000 0000 */
int manual_mode = 0x1840; /* 0b 0001 1000 0100 0000 */
uint8_t tx[2];
uint8_t rx[2];
- struct spi_device* spi_dev;
memset(tx, 0, sizeof(tx));
memset(rx, 0, sizeof(rx));
- if (strstr(attr->attr.name, ":0")) {
- if (!spi_ap1_adc_dev) {
- log_error("accessory card 1 adc device not present");
- return -ENODEV;
- }
-
- spi_dev = spi_ap1_adc_dev;
- } else if (strstr(attr->attr.name, ":1")) {
- if (!spi_ap2_adc_dev) {
- log_error("accessory card 2 adc device not present");
- return -ENODEV;
- }
-
- spi_dev = spi_ap2_adc_dev;
- } else {
- log_error("unknown adc device %s", attr->attr.name);
- return -ENODEV;
+ sscanf(attr->attr.name, "adc%d:%d", &channel, &port);
+ port_index = port - 1;
+ if (channel < 0 || channel > 2) {
+ log_error("channel [%d] is invalid", channel);
+ return -ENOENT;
}
-
- if (strstr(attr->attr.name, "adc0")) {
- channel = 0;
- } else if (strstr(attr->attr.name, "adc1")) {
- channel = 1;
- } else if (strstr(attr->attr.name, "adc2")) {
- channel = 2;
- } else {
- log_error("accessory card adc attr does not exist");
+ if (port < 1 || port > NUM_AP) {
+ log_error("port [%d] is invalid", port);
return -ENOENT;
}
@@ -294,7 +331,7 @@ static ssize_t mts_attr_show_ap_adc(struct device *dev, struct device_attribute
tx_data = manual_mode | ((channel << 7) & channel_mask);
tx[0] = tx_data >> 8;
tx[1] = tx_data & 0xFF;
- tmp = spi_writen(spi_dev, tx, 2);
+ tmp = spi_writen(gpiob_spi[port_index][adc], tx, 2);
if (tmp) {
log_error("spi_write failed %d", tmp);
return tmp;
@@ -305,14 +342,14 @@ static ssize_t mts_attr_show_ap_adc(struct device *dev, struct device_attribute
* the ADC just needs the clock running so it can convert */
tx[0] = 0;
tx[1] = 0;
- tmp = spi_writen(spi_dev, tx, 2);
+ tmp = spi_writen(gpiob_spi[port_index][adc], tx, 2);
if (tmp) {
log_error("2nd spi_write failed %d", tmp);
return tmp;
}
/* 3rd transfer to read data */
- tmp = spi_readn(spi_dev, rx, 2);
+ tmp = spi_readn(gpiob_spi[port_index][adc], rx, 2);
if (tmp) {
log_error("spi_read failed %d", tmp);
return tmp;
@@ -322,88 +359,165 @@ static ssize_t mts_attr_show_ap_adc(struct device *dev, struct device_attribute
return sprintf(buf, "%lu\n", (unsigned long) rx_data);
}
-/* accessory port 1 gpiob attributes */
-static DEVICE_ATTR_RO_MTS(dev_attr_ap1_gpio_din0, "din0:0", mts_attr_show_ap_din);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap1_gpio_din1, "din1:0", mts_attr_show_ap_din);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap1_gpio_din2, "din2:0", mts_attr_show_ap_din);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap1_gpio_din3, "din3:0", mts_attr_show_ap_din);
-static DEVICE_ATTR_MTS(dev_attr_ap1_gpio_dout0, "dout0:0", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_MTS(dev_attr_ap1_gpio_dout1, "dout1:0", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_MTS(dev_attr_ap1_gpio_dout2, "dout2:0", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_MTS(dev_attr_ap1_gpio_dout3, "dout3:0", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap1_gpio_adc0, "adc0:0", mts_attr_show_ap_adc);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap1_gpio_adc1, "adc1:0", mts_attr_show_ap_adc);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap1_gpio_adc2, "adc2:0", mts_attr_show_ap_adc);
-static DEVICE_ATTR_MTS(dev_attr_ap1_gpio_led1, "ap1-led1", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-static DEVICE_ATTR_MTS(dev_attr_ap1_gpio_led2, "ap1-led2", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-static DEVICE_ATTR_MTS(dev_attr_ap1_gpio_oe, "ap1-dout-enable", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-static DEVICE_ATTR_MTS(dev_attr_ap1_reset, "ap1-reset", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-
-static int ap1_gpio_attributes_size = 15; // not including NULL at end
-
-static struct attribute *ap1_gpio_attributes[] = {
- &dev_attr_ap1_reset.attr,
-
- &dev_attr_ap1_gpio_oe.attr, // gpio1
- &dev_attr_ap1_gpio_led1.attr, // gpio3
- &dev_attr_ap1_gpio_led2.attr, // gpio4
-
- &dev_attr_ap1_gpio_din0.attr,
- &dev_attr_ap1_gpio_din1.attr,
- &dev_attr_ap1_gpio_din2.attr,
- &dev_attr_ap1_gpio_din3.attr,
-
- &dev_attr_ap1_gpio_dout0.attr,
- &dev_attr_ap1_gpio_dout1.attr,
- &dev_attr_ap1_gpio_dout2.attr,
- &dev_attr_ap1_gpio_dout3.attr,
-
- &dev_attr_ap1_gpio_adc0.attr,
- &dev_attr_ap1_gpio_adc1.attr,
- &dev_attr_ap1_gpio_adc2.attr,
-
- NULL,
-};
+static bool gpiob_spi_driver_setup(struct spi_driver *driver, const char *driver_name) {
+ char* name = kstrdup(driver_name, GFP_KERNEL);
+ if (! name) {
+ log_error("GFP_KERNEL dup failed for driver [%s]", driver_name);
+ return false;
+ }
+ driver->driver.name = name;
+ driver->driver.bus = &spi_bus_type;
+ driver->driver.owner = THIS_MODULE;
+ driver->probe = mts_spi_ap_probe;
+ driver->remove = mts_spi_ap_remove;
+
+ return true;
+}
+
+// 4 digital inputs
+// 4 digital outputs
+// 3 analog to digital
+// 2 LEDs
+// 1 digital out enable
+// 1 reset
+static int ap_gpiob_attrs_size = 15;
+
+static bool gpiob_setup(enum ap port) {
+ int i;
+ int port_index = port - 1;
+ struct kobj_attribute *attr;
+ char buf[32];
+
+ log_info("loading GPIOB accessory card in port %d", port);
+
+ if (device_attrs_size + ap_gpiob_attrs_size >= device_attrs_max_size) {
+ log_error("can't load GPIOB accessory card in port %d - not enough room for attributes", port);
+ return false;
+ }
+
+ // add digital inputs
+ for (i = 0; i < 4; i++) {
+ sprintf(buf, "din%d:%d", i, port);
+ attr = create_attribute(buf, MTS_ATTR_MODE_RO);
+ if (! attr) {
+ log_error("failed to create attribute[%s]", buf);
+ return false;
+ }
+ attr->show = mts_attr_show_ap_din;
+ device_attrs[device_attrs_size++] = &attr->attr;
+ }
+
+ // add digital outputs
+ for (i = 0; i < 4; i++) {
+ sprintf(buf, "dout%d:%d", i, port);
+ attr = create_attribute(buf, MTS_ATTR_MODE_RW);
+ if (! attr) {
+ log_error("failed to create attribute[%s]", buf);
+ return false;
+ }
+ attr->show = mts_attr_show_ap_dout;
+ attr->store = mts_attr_store_ap_dout;
+ device_attrs[device_attrs_size++] = &attr->attr;
+ }
+
+ // add analog to digital
+ for (i = 0; i < 3; i++) {
+ sprintf(buf, "adc%d:%d", i, port);
+ attr = create_attribute(buf, MTS_ATTR_MODE_RO);
+ if (! attr) {
+ log_error("failed to create attribute[%s]", buf);
+ return false;
+ }
+ attr->show = mts_attr_show_ap_adc;
+ device_attrs[device_attrs_size++] = &attr->attr;
+ }
+
+ // add LEDs
+ for (i = 1; i <= 2; i++) {
+ sprintf(buf, "ap-led%d:%d", i, port);
+ attr = create_attribute(buf, MTS_ATTR_MODE_RW);
+ if (! attr) {
+ log_error("failed to create attribute[%s]", buf);
+ return false;
+ }
+ attr->show = mts_attr_show_ap_gpio_pin;
+ attr->store = mts_attr_store_ap_gpio_pin;
+ device_attrs[device_attrs_size++] = &attr->attr;
+ }
+
+ // misc attributes
+ sprintf(buf, "ap-dout-enable:%d", port);
+ attr = create_attribute(buf, MTS_ATTR_MODE_RW);
+ if (! attr) {
+ log_error("failed to create attribute[%s]", buf);
+ return false;
+ }
+ attr->show = mts_attr_show_ap_gpio_pin;
+ attr->store = mts_attr_store_ap_gpio_pin;
+ device_attrs[device_attrs_size++] = &attr->attr;
+
+ sprintf(buf, "ap-reset:%d", port);
+ attr = create_attribute(buf, MTS_ATTR_MODE_RW);
+ if (! attr) {
+ log_error("failed to create attribute[%s]", buf);
+ return false;
+ }
+ attr->show = mts_attr_show_ap_gpio_pin;
+ attr->store = mts_attr_store_ap_gpio_pin;
+ device_attrs[device_attrs_size++] = &attr->attr;
+
+ // setup and register drivers
+ log_debug("registering accessory card %d dout driver", port);
+ sprintf(buf, "mts-io-ap%d-dout", port);
+ if (! gpiob_spi_driver_setup(&gpiob_spi_drivers[port_index][dout], buf)) {
+ log_error("failed to set up spi driver [%s]", buf);
+ return false;
+ }
+ if (spi_register_driver(&gpiob_spi_drivers[port_index][dout])) {
+ log_error("failed to register accessory card %d dout driver", port);
+ spi_unregister_driver(&gpiob_spi_drivers[port_index][dout]);
+ return false;
+ }
+
+ log_debug("registering accessory card %d din driver", port);
+ sprintf(buf, "mts-io-ap%d-din", port);
+ if (! gpiob_spi_driver_setup(&gpiob_spi_drivers[port_index][din], buf)) {
+ log_error("failed to set up spi driver [%s]", buf);
+ return false;
+ }
+ if (spi_register_driver(&gpiob_spi_drivers[port_index][din])) {
+ log_error("failed to register accessory card %d din driver", port);
+ spi_unregister_driver(&gpiob_spi_drivers[port_index][din]);
+ return false;
+ }
+
+ log_debug("registering accessory card %d adc driver", port);
+ sprintf(buf, "mts-io-ap%d-adc", port);
+ if (! gpiob_spi_driver_setup(&gpiob_spi_drivers[port_index][adc], buf)) {
+ log_error("failed to set up spi driver [%s]", buf);
+ return false;
+ }
+ if (spi_register_driver(&gpiob_spi_drivers[port_index][adc])) {
+ log_error("failed to register accessory card %d adc driver", port);
+ spi_unregister_driver(&gpiob_spi_drivers[port_index][adc]);
+ return false;
+ }
+ return true;
+}
+
+static bool gpiob_teardown(enum ap port) {
+ int port_index = port - 1;
+
+ // do we need to clean up allocated memory here as well?
+ log_info("unloading GPIOB accessory card in port %d", port);
+ spi_unregister_driver(&gpiob_spi_drivers[port_index][dout]);
+ spi_unregister_driver(&gpiob_spi_drivers[port_index][din]);
+ spi_unregister_driver(&gpiob_spi_drivers[port_index][adc]);
+ return true;
+}
-/* accessory port 2 gpiob attributes */
-static DEVICE_ATTR_RO_MTS(dev_attr_ap2_gpio_din0, "din0:1", mts_attr_show_ap_din);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap2_gpio_din1, "din1:1", mts_attr_show_ap_din);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap2_gpio_din2, "din2:1", mts_attr_show_ap_din);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap2_gpio_din3, "din3:1", mts_attr_show_ap_din);
-static DEVICE_ATTR_MTS(dev_attr_ap2_gpio_dout0, "dout0:1", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_MTS(dev_attr_ap2_gpio_dout1, "dout1:1", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_MTS(dev_attr_ap2_gpio_dout2, "dout2:1", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_MTS(dev_attr_ap2_gpio_dout3, "dout3:1", mts_attr_show_ap_dout, mts_attr_store_ap_dout);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap2_gpio_adc0, "adc0:1", mts_attr_show_ap_adc);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap2_gpio_adc1, "adc1:1", mts_attr_show_ap_adc);
-static DEVICE_ATTR_RO_MTS(dev_attr_ap2_gpio_adc2, "adc2:1", mts_attr_show_ap_adc);
-static DEVICE_ATTR_MTS(dev_attr_ap2_gpio_led1, "ap2-led1", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-static DEVICE_ATTR_MTS(dev_attr_ap2_gpio_led2, "ap2-led2", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-static DEVICE_ATTR_MTS(dev_attr_ap2_gpio_oe, "ap2-dout-enable", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-static DEVICE_ATTR_MTS(dev_attr_ap2_reset, "ap2-reset", mts_attr_show_ap_gpio_pin, mts_attr_store_ap_gpio_pin);
-
-static int ap2_gpio_attributes_size = 15; // not including NULL at end
-
-static struct attribute *ap2_gpio_attributes[] = {
- &dev_attr_ap2_reset.attr,
-
- &dev_attr_ap2_gpio_oe.attr, // gpio1
- &dev_attr_ap2_gpio_led1.attr, // gpio3
- &dev_attr_ap2_gpio_led2.attr, // gpio4
-
- &dev_attr_ap2_gpio_din0.attr,
- &dev_attr_ap2_gpio_din1.attr,
- &dev_attr_ap2_gpio_din2.attr,
- &dev_attr_ap2_gpio_din3.attr,
-
- &dev_attr_ap2_gpio_dout0.attr,
- &dev_attr_ap2_gpio_dout1.attr,
- &dev_attr_ap2_gpio_dout2.attr,
- &dev_attr_ap2_gpio_dout3.attr,
-
- &dev_attr_ap2_gpio_adc0.attr,
- &dev_attr_ap2_gpio_adc1.attr,
- &dev_attr_ap2_gpio_adc2.attr,
-
- NULL,
+static struct ap_info gpiob_info = {
+ .product_id = MTAC_GPIOB_0_0,
+ .setup = &gpiob_setup,
+ .teardown = &gpiob_teardown
};