diff options
-rw-r--r-- | io-module/mts_io.c | 344 |
1 files changed, 335 insertions, 9 deletions
diff --git a/io-module/mts_io.c b/io-module/mts_io.c index a7a5d75..b2c5045 100644 --- a/io-module/mts_io.c +++ b/io-module/mts_io.c @@ -641,6 +641,14 @@ static struct gpio_pin gpio_pins_mtr2_0_0[] = { .use_pullup = 0, }, { + .name = "NDC_EEPROM_WRITE_PROTECT", + .attr_name = "dc-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, @@ -688,6 +696,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, + }, { }, }; @@ -1168,6 +1224,24 @@ 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_board_temp_dev; static unsigned int board_temp_max_speed_hz = 1 * 1000 * 1000; module_param(board_temp_max_speed_hz, uint, S_IRUGO); @@ -1576,12 +1650,37 @@ static int ADT7302_to_celsius(int value) return value; } +static const char *daughter_card_normalize_attribute_names(const char *name) { + switch (mts_dc_product_id) { + case MTDC_GPIOB_0_0: + if (! strcmp(name, "dc-led1")) { + return "dc-gpio1"; + } else if (! strcmp(name, "dc-led2")) { + return "dc-gpio2"; + } else if (! strcmp(name, "dc-oe")) { + return "dc-gpio3"; + } else { + log_error("cannot normalize attribute %s to standard daughter card GPIO pin names", name); + return "unavailable"; + } + + default: + log_error("daughter card %d not supported at this time", mts_dc_product_id); + return "unavailable"; + } +} + static ssize_t mts_attr_show_gpio_pin(struct device *dev, struct device_attribute *attr, char *buf) { int value; - struct gpio_pin *pin = gpio_pin_by_attr_name(attr->attr.name); + struct gpio_pin *pin; + if (strstr(attr->attr.name, "dc-")) { + pin = gpio_pin_by_attr_name(daughter_card_normalize_attribute_names(attr->attr.name)); + } else { + pin = gpio_pin_by_attr_name(attr->attr.name); + } if (!pin) { return -ENODEV; @@ -1609,7 +1708,12 @@ static ssize_t mts_attr_store_gpio_pin(struct device *dev, { int value; int err; - struct gpio_pin *pin = gpio_pin_by_attr_name(attr->attr.name); + struct gpio_pin *pin; + if (strstr(attr->attr.name, "dc-")) { + pin = gpio_pin_by_attr_name(daughter_card_normalize_attribute_names(attr->attr.name)); + } else { + pin = gpio_pin_by_attr_name(attr->attr.name); + } if (!pin) { return -ENODEV; @@ -2500,20 +2604,112 @@ static DEVICE_ATTR_RO_MTS(dev_attr_eth_mac, "mac-eth", static ssize_t mts_attr_show_dc_din(struct device *dev, struct device_attribute *attr, char *buf) { - /* TODO: actually write this function */ - return sprintf(buf, "%d\n", 0); + 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, "dc-din0")) { + bit = BIT(0); + } else if (!strcmp(attr->attr.name, "dc-din1")) { + bit = BIT(1); + } else if (!strcmp(attr->attr.name, "dc-din2")) { + bit = BIT(2); + } else if (!strcmp(attr->attr.name, "dc-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) { - /* TODO: actually write this function */ - return 0; + int value; + u8 bit; + + if (!spi_dc_dout_dev) { + log_error("dc dout device not present"); + return -ENODEV; + } + + if (!strcmp(attr->attr.name, "dc-dout0")) { + bit = BIT(0); + } else if (!strcmp(attr->attr.name, "dc-dout1")) { + bit = BIT(1); + } else if (!strcmp(attr->attr.name, "dc-dout2")) { + bit = BIT(2); + } else if (!strcmp(attr->attr.name, "dc-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) { - /* TODO: actually write this function */ - return sprintf(buf, "%d\n", 0); + int value; + u8 bit; + + if (!spi_dc_dout_dev) { + log_error("dc dout device not present"); + return -ENODEV; + } + + if (!strcmp(attr->attr.name, "dc-dout0")) { + bit = BIT(0); + } else if (!strcmp(attr->attr.name, "dc-dout1")) { + bit = BIT(1); + } else if (!strcmp(attr->attr.name, "dc-dout2")) { + bit = BIT(2); + } else if (!strcmp(attr->attr.name, "dc-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) @@ -2522,7 +2718,7 @@ static ssize_t mts_attr_show_dc_adc(struct device *dev, struct device_attribute return sprintf(buf, "%lu\n", (unsigned long) 0); } -/* daughter card gpio */ +/* MTDC-GPIOB */ static DEVICE_ATTR_RO_MTS(dev_attr_dc_din0, "dc-din0", mts_attr_show_dc_din); static DEVICE_ATTR_RO_MTS(dev_attr_dc_din1, "dc-din1", mts_attr_show_dc_din); static DEVICE_ATTR_RO_MTS(dev_attr_dc_din2, "dc-din2", mts_attr_show_dc_din); @@ -2534,6 +2730,9 @@ static DEVICE_ATTR_MTS(dev_attr_dc_dout3, "dc-dout3", mts_attr_show_dc_dout, mts static DEVICE_ATTR_RO_MTS(dev_attr_dc_adc0, "dc-adc0", mts_attr_show_dc_adc); static DEVICE_ATTR_RO_MTS(dev_attr_dc_adc1, "dc-adc1", mts_attr_show_dc_adc); static DEVICE_ATTR_RO_MTS(dev_attr_dc_adc2, "dc-adc2", mts_attr_show_dc_adc); +static DEVICE_ATTR_MTS(dev_attr_dc_led1, "dc-led1", mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); +static DEVICE_ATTR_MTS(dev_attr_dc_led2, "dc-led2", mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); +static DEVICE_ATTR_MTS(dev_attr_dc_oe, "dc-oe", mts_attr_show_gpio_pin, mts_attr_store_gpio_pin); static struct attribute *mt100eocg_platform_attributes[] = { &dev_attr_vendor_id.attr, @@ -2636,6 +2835,11 @@ struct attribute *mtr2_platform_attributes[] = { 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, }; @@ -2654,6 +2858,10 @@ static struct attribute *mtr2_daughter_card_attributes[] = { &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, }; @@ -2929,6 +3137,95 @@ 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_board_temp_probe(struct spi_device *spi) { int tmp; @@ -3173,6 +3470,21 @@ static int __init mts_io_init(void) } else { log_info("successfully added GPIO daughter card attributes"); } + + log_info("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_info("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; + } break; default: @@ -3338,6 +3650,18 @@ 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); + 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"); @@ -3359,3 +3683,5 @@ 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"); |