diff options
author | Mike Fiore <mfiore@multitech.com> | 2014-02-14 10:23:53 -0600 |
---|---|---|
committer | Mike Fiore <mfiore@multitech.com> | 2014-02-14 10:23:53 -0600 |
commit | 8375b880a83b15c63c487f4e75f9105dcdca575f (patch) | |
tree | 1bc1e31dbdcf6c90ae1dbf289edb71a5f50598f7 | |
parent | 9b57404a2b91e356dbed48b266036c57d8a8c62f (diff) | |
parent | 4d38e64ecee05c0de657757aee26a4c2f852dbc4 (diff) | |
download | cdp-io-controller-8375b880a83b15c63c487f4e75f9105dcdca575f.tar.gz cdp-io-controller-8375b880a83b15c63c487f4e75f9105dcdca575f.tar.bz2 cdp-io-controller-8375b880a83b15c63c487f4e75f9105dcdca575f.zip |
Merge branch 'daughter-cards'
-rw-r--r-- | io-module/Makefile | 1 | ||||
-rw-r--r-- | io-module/mts_io.c | 675 | ||||
-rw-r--r-- | io-module/mts_io.h | 33 |
3 files changed, 700 insertions, 9 deletions
diff --git a/io-module/Makefile b/io-module/Makefile index 5d036f4..f95a55e 100644 --- a/io-module/Makefile +++ b/io-module/Makefile @@ -1,4 +1,5 @@ obj-m := mts_io.o +CFLAGS_mts_io.o := ${DAUGHTER_CARD} clean: rm -f *.ko *.o diff --git a/io-module/mts_io.c b/io-module/mts_io.c index 89e1e0e..5a30e2e 100644 --- a/io-module/mts_io.c +++ b/io-module/mts_io.c @@ -83,10 +83,23 @@ static int led_mode_status = LED_OFF; #define SOUT_LED_SIG3_BIT BIT(6) #define SOUT_EXTSERIAL_DCD_BIT BIT(7) +/* on-board EEPROM */ extern uint8_t mts_id_eeprom[512]; static struct mts_id_eeprom_layout id_eeprom; +/* daughter card EEPROM */ +#ifdef MTOCGD2 +extern uint8_t mts_dc_eeprom[512]; +#else +uint8_t mts_dc_eeprom[512] = {}; +#endif +static struct mts_dc_eeprom_layout dc_eeprom; + +bool daughter_card_capable = false; +bool has_daughter_card = false; + static uint8_t mts_product_id; +static uint8_t mts_dc_product_id; static uint8_t has_spi_sout; static uint8_t has_spi_din; static uint8_t has_spi_dout; @@ -632,6 +645,14 @@ static struct gpio_pin gpio_pins_mtr2_0_0[] = { .use_pullup = 0, }, { + .name = "NDC_EEPROM_WRITE_PROTECT", + .attr_name = "ndc-eeprom-wp", + .pin = AT91_PIN_PC26, + .direction = GPIO_DIR_OUTPUT, + .output_value = 0, + .use_pullup = 0, + }, + { .name = "BT_EN", .attr_name = "bt-enabled", .pin = AT91_PIN_PD21, @@ -679,6 +700,54 @@ static struct gpio_pin gpio_pins_mtr2_0_0[] = { .output_value = 0, .use_pullup = 0, }, + { + .name = "NDC_GPIO1", + .attr_name = "dc-gpio1", + .pin = AT91_PIN_PC0, + .direction = GPIO_DIR_OUTPUT, + .output_value = 0, + .use_pullup = 0, + }, + { + .name = "NDC_GPIO2", + .attr_name = "dc-gpio2", + .pin = AT91_PIN_PC14, + .direction = GPIO_DIR_OUTPUT, + .output_value = 0, + .use_pullup = 0, + }, + { + .name = "NDC_GPIO3", + .attr_name = "dc-gpio3", + .pin = AT91_PIN_PC29, + .direction = GPIO_DIR_OUTPUT, + .output_value = 0, + .use_pullup = 0, + }, + { + .name = "NDC_GPIO4", + .attr_name = "dc-gpio4", + .pin = AT91_PIN_PC30, + .direction = GPIO_DIR_OUTPUT, + .output_value = 0, + .use_pullup = 0, + }, + { + .name = "NDC_INTERRUPT1", + .attr_name = "dc-int1", + .pin = AT91_PIN_PC20, + .direction = GPIO_DIR_INPUT, + .output_value = 0, + .use_pullup = 0, + }, + { + .name = "NDC_INTERRUPT2", + .attr_name = "dc-int2", + .pin = AT91_PIN_PC21, + .direction = GPIO_DIR_INPUT, + .output_value = 0, + .use_pullup = 0, + }, { }, }; @@ -1159,6 +1228,32 @@ MODULE_PARM_DESC( "Maximum clock rate to be used with this device (default: 1 MHz)" ); +static struct spi_device *spi_dc_dout_dev; +static u8 spi_dc_dout_value; +static DEFINE_MUTEX(spi_dc_dout_mutex); +static unsigned int dc_dout_max_speed_hz = 1 * 1000 * 1000; +module_param(dc_dout_max_speed_hz, uint, S_IRUGO); +MODULE_PARM_DESC( + dc_dout_max_speed_hz, + "Maximum clock rate to be used with this device (default: 1 MHz)" +); + +static struct spi_device *spi_dc_din_dev; +static unsigned int dc_din_max_speed_hz = 1 * 1000 * 1000; +module_param(dc_din_max_speed_hz, uint, S_IRUGO); +MODULE_PARM_DESC( + dc_din_max_speed_hz, + "Maximum clock rate to be used with this device (default: 1 MHz)" +); + +static struct spi_device *spi_dc_adc_dev; +static unsigned int dc_adc_max_speed_hz = 20 * 1000 * 1000; +module_param(dc_adc_max_speed_hz, uint, S_IRUGO); +MODULE_PARM_DESC( + dc_adc_max_speed_hz, + "Maximum clock rate to be used with this device (default: 20 MHz)" +); + static struct spi_device *spi_board_temp_dev; static unsigned int board_temp_max_speed_hz = 1 * 1000 * 1000; module_param(board_temp_max_speed_hz, uint, S_IRUGO); @@ -2489,6 +2584,281 @@ static DEVICE_ATTR_RO_MTS(dev_attr_wifi_mac, "mac-wifi", static DEVICE_ATTR_RO_MTS(dev_attr_eth_mac, "mac-eth", mts_attr_show_product_info); +struct gpio_pin *dc_gpio_pin_by_attr_name(const char *name) { + struct gpio_pin *pin; + char *pin_attr_name; + + if (!strcmp(name, "led1")) { + pin_attr_name = "dc-gpio1"; + } else if (!strcmp(name, "led2")) { + pin_attr_name = "dc-gpio2"; + } else if (!strcmp(name, "dout-enable")) { + pin_attr_name = "dc-gpio3"; + } else { + log_error("daughter card attribute %s not available", name); + return NULL; + } + + for (pin = gpio_pins; *pin->name; pin++) { + if (!strcmp(pin->attr_name, pin_attr_name)) { + return pin; + } + } + + log_error("pin with attr name %s not found", name); + + return NULL; +} + + +static ssize_t mts_attr_show_dc_gpio_pin(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int value; + struct gpio_pin *pin = dc_gpio_pin_by_attr_name(attr->attr.name); + + if (!pin) { + return -ENODEV; + } + + mutex_lock(&mts_io_mutex); + + value = at91_get_gpio_value(pin->pin); + + mutex_unlock(&mts_io_mutex); + + if (value < 0) { + return value; + } + + if (pin->active_low) { + value = !value; + } + + return sprintf(buf, "%d\n", value); +} + +static ssize_t mts_attr_store_dc_gpio_pin(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int value; + int err; + struct gpio_pin *pin = dc_gpio_pin_by_attr_name(attr->attr.name); + + if (!pin) { + return -ENODEV; + } + + if (sscanf(buf, "%i", &value) != 1) { + return -EINVAL; + } + + if (pin->active_low) { + value = !value; + } + + mutex_lock(&mts_io_mutex); + + err = at91_set_gpio_value(pin->pin, value); + + mutex_unlock(&mts_io_mutex); + + if (err) { + return err; + } + + return count; +} + +static ssize_t mts_attr_show_dc_din(struct device *dev, struct device_attribute *attr, char *buf) +{ + int tmp; + u8 bit; + u8 byte; + + if (!spi_dc_din_dev) { + log_error("dc din device not present"); + return -ENODEV; + } + + if (!strcmp(attr->attr.name, "din0")) { + bit = BIT(0); + } else if (!strcmp(attr->attr.name, "din1")) { + bit = BIT(1); + } else if (!strcmp(attr->attr.name, "din2")) { + bit = BIT(2); + } else if (!strcmp(attr->attr.name, "din3")) { + bit = BIT(3); + } else { + log_error("dc din attr does not exist"); + return -ENOENT; + } + + tmp = spi_readn(spi_dc_din_dev, &byte, 1); + if (tmp) { + log_error("spi_read failed %d", tmp); + return tmp; + } + + tmp = byte & bit ? 1 : 0; + + return sprintf(buf, "%d\n", tmp); +} + +static ssize_t mts_attr_store_dc_dout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int value; + u8 bit; + + if (!spi_dc_dout_dev) { + log_error("dc dout device not present"); + return -ENODEV; + } + + if (!strcmp(attr->attr.name, "dout0")) { + bit = BIT(0); + } else if (!strcmp(attr->attr.name, "dout1")) { + bit = BIT(1); + } else if (!strcmp(attr->attr.name, "dout2")) { + bit = BIT(2); + } else if (!strcmp(attr->attr.name, "dout3")) { + bit = BIT(3); + } else { + log_error("dc dout attr does not exist"); + return -ENOENT; + } + + if (sscanf(buf, "%i", &value) != 1) { + log_error("dc dout attr invalid argument"); + return -EINVAL; + } + + mutex_lock(&spi_dc_dout_mutex); + + if (value) { + spi_dc_dout_value &= ~bit; + } else { + spi_dc_dout_value |= bit; + } + + spi_writen(spi_dc_dout_dev, &spi_dc_dout_value, 1); + + mutex_unlock(&spi_dc_dout_mutex); + + return count; +} + +static ssize_t mts_attr_show_dc_dout(struct device *dev, struct device_attribute *attr, char *buf) +{ + int value; + u8 bit; + + if (!spi_dc_dout_dev) { + log_error("dc dout device not present"); + return -ENODEV; + } + + if (!strcmp(attr->attr.name, "dout0")) { + bit = BIT(0); + } else if (!strcmp(attr->attr.name, "dout1")) { + bit = BIT(1); + } else if (!strcmp(attr->attr.name, "dout2")) { + bit = BIT(2); + } else if (!strcmp(attr->attr.name, "dout3")) { + bit = BIT(3); + } else { + log_error("dc dout attr does not exist"); + return -ENOENT; + } + + mutex_lock(&spi_dc_dout_mutex); + + value = spi_dc_dout_value & bit ? 0 : 1; + + mutex_unlock(&spi_dc_dout_mutex); + + return sprintf(buf, "%d\n", value); +} + +static ssize_t mts_attr_show_dc_adc(struct device *dev, struct device_attribute *attr, char *buf) +{ + int tmp; + int tx_data; + int rx_data; + int channel; + 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]; + + if (!spi_dc_adc_dev) { + log_error("dc adc device not present"); + return -ENODEV; + } + + memset(tx, 0, sizeof(tx)); + memset(rx, 0, sizeof(rx)); + + if (!strcmp(attr->attr.name, "adc0")) { + channel = 0; + } else if (!strcmp(attr->attr.name, "adc1")) { + channel = 1; + } else if (! strcmp(attr->attr.name, "adc2")) { + channel = 2; + } else { + log_error("dc adc attr does not exist"); + return -ENOENT; + } + + /* 1st transfer to set up (5V reference, channel to read from) */ + tx_data = manual_mode | ((channel << 7) & channel_mask); + tx[0] = tx_data >> 8; + tx[1] = tx_data & 0xFF; + tmp = spi_writen(spi_dc_adc_dev, tx, 2); + if (tmp) { + log_error("spi_write failed %d", tmp); + return tmp; + } + + /* 2nd transfer to clock chip for ADC conversion + * this can be a throw-away read or an empty write, + * the ADC just needs the clock running so it can convert */ + tx[0] = 0; + tx[1] = 0; + tmp = spi_writen(spi_dc_adc_dev, tx, 2); + if (tmp) { + log_error("2nd spi_write failed %d", tmp); + return tmp; + } + + /* 3rd transfer to read data */ + tmp = spi_readn(spi_dc_adc_dev, rx, 2); + if (tmp) { + log_error("spi_read failed %d", tmp); + return tmp; + } + rx_data = ((rx[0] & 0x0F) << 8) | (rx[1] & 0xFF); + + return sprintf(buf, "%lu\n", (unsigned long) rx_data); +} + +/* MTDC-GPIOB */ +static DEVICE_ATTR_RO_MTS(dev_attr_dc_din0, "din0", mts_attr_show_dc_din); +static DEVICE_ATTR_RO_MTS(dev_attr_dc_din1, "din1", mts_attr_show_dc_din); +static DEVICE_ATTR_RO_MTS(dev_attr_dc_din2, "din2", mts_attr_show_dc_din); +static DEVICE_ATTR_RO_MTS(dev_attr_dc_din3, "din3", mts_attr_show_dc_din); +static DEVICE_ATTR_MTS(dev_attr_dc_dout0, "dout0", mts_attr_show_dc_dout, mts_attr_store_dc_dout); +static DEVICE_ATTR_MTS(dev_attr_dc_dout1, "dout1", mts_attr_show_dc_dout, mts_attr_store_dc_dout); +static DEVICE_ATTR_MTS(dev_attr_dc_dout2, "dout2", mts_attr_show_dc_dout, mts_attr_store_dc_dout); +static DEVICE_ATTR_MTS(dev_attr_dc_dout3, "dout3", mts_attr_show_dc_dout, mts_attr_store_dc_dout); +static DEVICE_ATTR_RO_MTS(dev_attr_dc_adc0, "adc0", mts_attr_show_dc_adc); +static DEVICE_ATTR_RO_MTS(dev_attr_dc_adc1, "adc1", mts_attr_show_dc_adc); +static DEVICE_ATTR_RO_MTS(dev_attr_dc_adc2, "adc2", mts_attr_show_dc_adc); +static DEVICE_ATTR_MTS(dev_attr_dc_led1, "led1", mts_attr_show_dc_gpio_pin, mts_attr_store_dc_gpio_pin); +static DEVICE_ATTR_MTS(dev_attr_dc_led2, "led2", mts_attr_show_dc_gpio_pin, mts_attr_store_dc_gpio_pin); +static DEVICE_ATTR_MTS(dev_attr_dc_oe, "dout-enable", mts_attr_show_dc_gpio_pin, mts_attr_store_dc_gpio_pin); + static struct attribute *mt100eocg_platform_attributes[] = { &dev_attr_vendor_id.attr, &dev_attr_product_id.attr, @@ -2536,7 +2906,7 @@ static struct attribute_group mt100eocg_platform_attribute_group = { .attrs = mt100eocg_platform_attributes }; -static struct attribute *mtr2_platform_attributes[] = { +struct attribute *mtr2_platform_attributes[] = { &dev_attr_vendor_id.attr, &dev_attr_product_id.attr, &dev_attr_device_id.attr, @@ -2576,6 +2946,47 @@ static struct attribute *mtr2_platform_attributes[] = { &dev_attr_board_temperature.attr, + /* extra space for the daughter card attributes */ + NULL, // index 34 + NULL, // index 35 + NULL, // index 36 + NULL, // index 37 + NULL, // index 38 + NULL, // index 39 + NULL, // index 40 + NULL, // index 41 + NULL, // index 42 + NULL, // index 43 + NULL, // index 44 + NULL, // index 45 + NULL, // index 46 + NULL, // index 47 + NULL, // index 48 + NULL, // index 49 + NULL, // index 50 + NULL, // index 51 + NULL, +}; + +static struct attribute *mtr2_daughter_card_attributes[] = { + &dev_attr_dc_din0.attr, + &dev_attr_dc_din1.attr, + &dev_attr_dc_din2.attr, + &dev_attr_dc_din3.attr, + + &dev_attr_dc_dout0.attr, + &dev_attr_dc_dout1.attr, + &dev_attr_dc_dout2.attr, + &dev_attr_dc_dout3.attr, + + &dev_attr_dc_adc0.attr, + &dev_attr_dc_adc1.attr, + &dev_attr_dc_adc2.attr, + + &dev_attr_dc_led1.attr, + &dev_attr_dc_led2.attr, + &dev_attr_dc_oe.attr, + NULL, }; @@ -2583,6 +2994,32 @@ static struct attribute_group mtr2_platform_attribute_group = { .attrs = mtr2_platform_attributes }; +bool mtr2_add_daughter_card_attributes() +{ + size_t platform_attrs_size = sizeof(mtr2_platform_attributes) / sizeof(struct attribute *); + size_t daughter_card_attrs_size = sizeof(mtr2_daughter_card_attributes) / sizeof(struct attribute *); + size_t platform_attrs_index; + size_t daughter_card_attrs_index; + size_t copy_length = daughter_card_attrs_size - 1; /* don't need to copy the NULL at the end */ + + for (platform_attrs_index = 0; platform_attrs_index < platform_attrs_size; platform_attrs_index++) { + if (! mtr2_platform_attributes[platform_attrs_index]) { + break; + } + } + + if (platform_attrs_size < platform_attrs_index + daughter_card_attrs_size) { + log_error("not enough room for MTR2 daughter card attributes!"); + return false; + } + + for (daughter_card_attrs_index = 0; daughter_card_attrs_index < copy_length; daughter_card_attrs_index++, platform_attrs_index++) { + mtr2_platform_attributes[platform_attrs_index] = mtr2_daughter_card_attributes[daughter_card_attrs_index]; + } + + return true; +} + static struct attribute *mtcdp_platform_attributes[] = { &dev_attr_vendor_id.attr, &dev_attr_product_id.attr, @@ -2825,6 +3262,139 @@ static struct spi_driver mts_spi_din_driver = { .remove = __devexit_p(mts_spi_din_remove), }; +static int __devinit mts_spi_dc_dout_probe(struct spi_device *spi) +{ + int tmp; + + if (! has_daughter_card || mts_dc_product_id != MTDC_GPIOB_0_0) { + log_error("daughter card digital outputs not available"); + return -ENODEV; + } + + spi->max_speed_hz = dc_dout_max_speed_hz; + spi->mode = 0; + + log_debug("dc_dout_max_speed_hz: %d", dc_dout_max_speed_hz); + + tmp = spi_setup(spi); + if (tmp < 0) { + log_error("spi_setup dc dout failed"); + return tmp; + } + + spi_dc_dout_value = 0x00; + spi_writen(spi, &spi_dc_dout_value, 1); + + spi_dc_dout_dev = spi; + + return 0; +} + +static int mts_spi_dc_dout_remove(struct spi_device *spi) +{ + spi_dc_dout_dev = NULL; + + return 0; +} + +static struct spi_driver mts_spi_dc_dout_driver = { + .driver = { + .name = "mts-io-dc-dout", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = mts_spi_dc_dout_probe, + .remove = __devexit_p(mts_spi_dc_dout_remove), +}; + +static int __devinit mts_spi_dc_din_probe(struct spi_device *spi) +{ + int tmp; + + if (! has_daughter_card || mts_dc_product_id != MTDC_GPIOB_0_0) { + log_error("daughter card digital inputs not available"); + return -ENODEV; + } + + spi->max_speed_hz = dc_din_max_speed_hz; + spi->mode = SPI_CPOL; + + log_debug("dc_din_max_speed_hz: %d", dc_din_max_speed_hz); + + tmp = spi_setup(spi); + if (tmp < 0) { + log_error("spi_setup daughter card din failed"); + return tmp; + } + + spi_dc_din_dev = spi; + + return 0; +} + +static int mts_spi_dc_din_remove(struct spi_device *spi) +{ + spi_dc_din_dev = NULL; + + return 0; +} + +static struct spi_driver mts_spi_dc_din_driver = { + .driver = { + .name = "mts-io-dc-din", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = mts_spi_dc_din_probe, + .remove = __devexit_p(mts_spi_dc_din_remove), +}; + +static int __devinit mts_spi_dc_adc_probe(struct spi_device *spi) +{ + int tmp; + + if (! has_daughter_card || mts_dc_product_id != MTDC_GPIOB_0_0) { + log_error("daughter card analog to digital not available"); + return -ENODEV; + } + + spi->max_speed_hz = dc_adc_max_speed_hz; + spi->mode = 0; + + log_debug("dc_adc_max_speed_hz: %d", dc_adc_max_speed_hz); + log_debug("dc_adc_mode: %d", spi->mode); + + tmp = spi_setup(spi); + if (tmp < 0) { + log_error("spi_setup daughter card adc failed"); + return tmp; + } + + spi_dc_adc_dev = spi; + + return 0; +} + +static int mts_spi_dc_adc_remove(struct spi_device *spi) +{ + spi_dc_adc_dev = NULL; + + return 0; +} + +static struct spi_driver mts_spi_dc_adc_driver = { + .driver = { + .name = "mts-io-dc-adc", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = mts_spi_dc_adc_probe, + .remove = __devexit_p(mts_spi_dc_adc_remove), +}; + static int __devinit mts_spi_board_temp_probe(struct spi_device *spi) { int tmp; @@ -2863,6 +3433,36 @@ static struct spi_driver mts_spi_board_temp_driver = { .remove = __devexit_p(mts_spi_board_temp_remove), }; +static int mts_dc_eeprom_load(void) +{ + memcpy(&dc_eeprom, mts_dc_eeprom, sizeof(mts_dc_eeprom)); + + if (mts_dc_eeprom[0] == 0xFF) { + log_error("uninitialized eeprom on daughter card"); + return -EIO; + } else if (mts_dc_eeprom[0] == 0x00) { + log_info("no daughter card inserted"); + return 0; + } + + has_daughter_card = true; + + log_info("daughter card vendor-id: %.32s", dc_eeprom.vendor_id); + log_info("daughter card product-id: %.32s", dc_eeprom.product_id); + log_info("daughter card device-id: %.32s", dc_eeprom.device_id); + log_info("daughter card hw-version: %.32s", dc_eeprom.hw_version); + /* TODO: only show the mac address if this is the ethernet card */ + log_info("daughter card mac-addr: %02X:%02X:%02X:%02X:%02X:%02X", + dc_eeprom.mac_addr[0], + dc_eeprom.mac_addr[1], + dc_eeprom.mac_addr[2], + dc_eeprom.mac_addr[3], + dc_eeprom.mac_addr[4], + dc_eeprom.mac_addr[5]); + + return 0; +} + static int mts_id_eeprom_load(void) { memcpy(&id_eeprom, mts_id_eeprom, sizeof(mts_id_eeprom)); @@ -2901,6 +3501,7 @@ static int mts_id_eeprom_load(void) attr_group = &mtr2_platform_attribute_group; gpio_pins = gpio_pins_mtr2_0_0; mts_product_id = MTR2_0_0; + daughter_card_capable = true; has_spi_sout = 0; has_spi_din = 0; has_spi_dout = 0; @@ -2928,6 +3529,7 @@ static int mts_id_eeprom_load(void) attr_group = &mtr2_platform_attribute_group; gpio_pins = gpio_pins_mtr2_0_0; mts_product_id = MTOCGD3_0_0; + daughter_card_capable = true; has_spi_sout = 0; has_spi_din = 0; has_spi_dout = 0; @@ -3005,12 +3607,65 @@ static int __init mts_io_init(void) int ret; log_info("init: " DRIVER_VERSION); - + ret = mts_id_eeprom_load(); if (ret) { goto error1; } + if (daughter_card_capable) { + mts_dc_product_id = MTDC_NONE; + ret = mts_dc_eeprom_load(); + if (ret) { + /* error reading the EEPROM from the daughter card */ + log_error("error reading daughter card eeprom: %d", ret); + log_error("unable to initialize daughter card"); + goto error1; + } else if (has_daughter_card) { + /* no error and we have a daughter card */ + if (strstr(dc_eeprom.product_id, PRODUCT_ID_MTDC_GPIOB)) { + mts_dc_product_id = MTDC_GPIOB_0_0; + } + + switch(mts_dc_product_id) { + case MTDC_GPIOB_0_0: + log_debug("adding GPIO daughter card attributes"); + if (! mtr2_add_daughter_card_attributes()) { + log_error("failed to add GPIO daughter card attributes"); + goto error1; + } else { + log_info("successfully added GPIO daughter card attributes"); + } + + log_debug("registering daughter card dout driver"); + ret = spi_register_driver(&mts_spi_dc_dout_driver); + if (ret) { + log_error("failed to register dc dout driver"); + spi_unregister_driver(&mts_spi_dc_dout_driver); + goto error1; + } + log_debug("registering daughter card din driver"); + ret = spi_register_driver(&mts_spi_dc_din_driver); + if (ret) { + log_error("failed to register dc din driver"); + spi_unregister_driver(&mts_spi_dc_din_driver); + goto error1; + } + log_debug("registering daughter card adc driver"); + ret = spi_register_driver(&mts_spi_dc_adc_driver); + if (ret) { + log_error("failed to register dc adc driver"); + spi_unregister_driver(&mts_spi_dc_adc_driver); + goto error1; + } + break; + + default: + log_info("daughter card '%s' currently unsupported", dc_eeprom.product_id); + } + } + } + mts_io_platform_device = platform_device_alloc(PLATFORM_NAME, -1); if (!mts_io_platform_device) { ret = -ENOMEM; @@ -3168,6 +3823,19 @@ static void __exit mts_io_exit(void) if (has_spi_sout) spi_unregister_driver(&mts_spi_sout_driver); + if (has_daughter_card) { + switch (mts_dc_product_id) { + case MTDC_GPIOB_0_0: + spi_unregister_driver(&mts_spi_dc_dout_driver); + spi_unregister_driver(&mts_spi_dc_din_driver); + spi_unregister_driver(&mts_spi_dc_adc_driver); + break; + + default: + break; + } + } + sysfs_remove_group(&mts_io_platform_device->dev.kobj, attr_group); sysfs_remove_link(&mts_io_platform_device->dev.parent->kobj, "mtcdp"); @@ -3189,3 +3857,6 @@ MODULE_ALIAS("mts-io-sout"); MODULE_ALIAS("mts-io-board-temp"); MODULE_ALIAS("mts-io-dout"); MODULE_ALIAS("mts-io-din"); +MODULE_ALIAS("mts-io-dc-dout"); +MODULE_ALIAS("mts-io-dc-din"); +MODULE_ALIAS("mts-io-dc-adc"); diff --git a/io-module/mts_io.h b/io-module/mts_io.h index f2ff2b4..efbd8f8 100644 --- a/io-module/mts_io.h +++ b/io-module/mts_io.h @@ -28,18 +28,21 @@ struct device_attribute _dev_name = { \ #define VENDOR_ID_MULTITECH "Multi-Tech Systems" #define PRODUCT_ID_MTCDP_E1_DK "MTCDP-E1-DK" #define PRODUCT_ID_MT100EOCG "MT100EOCG" -#define PRODUCT_ID_MTR2 "MTR2" -#define PRODUCT_ID_MTR "MTR" -#define PRODUCT_ID_MTOCGD3 "MTOCGD3" -#define PRODUCT_ID_MTOCGD "MTOCGD" +#define PRODUCT_ID_MTR2 "MTR2" +#define PRODUCT_ID_MTR "MTR" +#define PRODUCT_ID_MTOCGD3 "MTOCGD3" +#define PRODUCT_ID_MTOCGD "MTOCGD" + +#define PRODUCT_ID_MTDC_GPIOB "MTDC-GPIOB" + #define HW_VERSION_MTCBA2_2_0 "MTCBA2-2.0" #define HW_VERSION_MTCDP_0_0 "MTCDP-0.0" #define HW_VERSION_MTCDP_1_0 "MTCDP-1.0" #define HW_VERSION_MT100EOCG_0_0 "MT100EOCG-0.0" -#define HW_VERSION_MTR2_0_0 "MTR2-0.0" -#define HW_VERSION_MTR_0_0 "MTR-0.0" -#define HW_VERSION_MTR_0_1 "MTR-0.1" +#define HW_VERSION_MTR2_0_0 "MTR2-0.0" +#define HW_VERSION_MTR_0_0 "MTR-0.0" +#define HW_VERSION_MTR_0_1 "MTR-0.1" #define HW_VERSION_MTOCGD3_0_0 "MTOCGD3-0.0" #define HW_VERSION_MTOCGD_0_0 "MTOCGD-0.0" #define HW_VERSION_MTOCGD_0_1 "MTOCGD-0.1" @@ -56,6 +59,11 @@ enum { MTOCGD_0_1, }; +enum { + MTDC_NONE, + MTDC_GPIOB_0_0, +}; + #define DEVICE_CAPA_INDEX(c) (((c) & 0xFF) >> 3) #define DEVICE_CAPA_MASK(c) BIT((c) & 0x07) @@ -81,6 +89,7 @@ do { \ #define CAPA_BLUETOOTH DEVICE_CAPA_VALUE(1, 7) #define CAPA_WIFI DEVICE_CAPA_VALUE(1, 6) +/* on-board EEPROM */ struct mts_id_eeprom_layout { char vendor_id[32]; char product_id[32]; @@ -94,6 +103,16 @@ struct mts_id_eeprom_layout { uint8_t reserved[302]; }; +/* daughter card EEPROM */ +struct mts_dc_eeprom_layout { + char vendor_id[32]; + char product_id[32]; + char device_id[32]; + char hw_version[32]; + uint8_t mac_addr[6]; + uint8_t reserved[378]; +}; + // GPIO pin types:input, output, open drain (1 = high Z, 0 = output low) enum { GPIO_DIR_INPUT, |