diff options
author | Mike Fiore <mfiore@multitech.com> | 2014-02-07 11:01:33 -0600 |
---|---|---|
committer | Mike Fiore <mfiore@multitech.com> | 2014-02-07 11:01:33 -0600 |
commit | 86fc87d06bb1c8c1d0dc8c5d846189df70c18395 (patch) | |
tree | 75af9743454addde36c9e437bf301afa18ca866e | |
parent | 01fdcfb50a2ac5b65f81f274e8329c20f6d7737d (diff) | |
download | cdp-io-controller-86fc87d06bb1c8c1d0dc8c5d846189df70c18395.tar.gz cdp-io-controller-86fc87d06bb1c8c1d0dc8c5d846189df70c18395.tar.bz2 cdp-io-controller-86fc87d06bb1c8c1d0dc8c5d846189df70c18395.zip |
finish GPIOB daughter card support
remove dc- prepend from daughter card attributes
set up driver, spi device, and functions for ADC chip
added functions to handle store/show for gpio lines
removed some unnecessary logging
-rw-r--r-- | io-module/mts_io.c | 302 |
1 files changed, 238 insertions, 64 deletions
diff --git a/io-module/mts_io.c b/io-module/mts_io.c index b2c5045..c56461e 100644 --- a/io-module/mts_io.c +++ b/io-module/mts_io.c @@ -642,7 +642,7 @@ static struct gpio_pin gpio_pins_mtr2_0_0[] = { }, { .name = "NDC_EEPROM_WRITE_PROTECT", - .attr_name = "dc-eeprom-wp", + .attr_name = "ndc-eeprom-wp", .pin = AT91_PIN_PC26, .direction = GPIO_DIR_OUTPUT, .output_value = 0, @@ -1242,6 +1242,14 @@ MODULE_PARM_DESC( "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); @@ -1650,37 +1658,12 @@ 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; - 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); - } + struct gpio_pin *pin = gpio_pin_by_attr_name(attr->attr.name); if (!pin) { return -ENODEV; @@ -1708,12 +1691,7 @@ static ssize_t mts_attr_store_gpio_pin(struct device *dev, { int value; int err; - 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); - } + struct gpio_pin *pin = gpio_pin_by_attr_name(attr->attr.name); if (!pin) { return -ENODEV; @@ -2602,6 +2580,93 @@ 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; @@ -2613,13 +2678,13 @@ static ssize_t mts_attr_show_dc_din(struct device *dev, struct device_attribute return -ENODEV; } - if (!strcmp(attr->attr.name, "dc-din0")) { + if (!strcmp(attr->attr.name, "din0")) { bit = BIT(0); - } else if (!strcmp(attr->attr.name, "dc-din1")) { + } else if (!strcmp(attr->attr.name, "din1")) { bit = BIT(1); - } else if (!strcmp(attr->attr.name, "dc-din2")) { + } else if (!strcmp(attr->attr.name, "din2")) { bit = BIT(2); - } else if (!strcmp(attr->attr.name, "dc-din3")) { + } else if (!strcmp(attr->attr.name, "din3")) { bit = BIT(3); } else { log_error("dc din attr does not exist"); @@ -2647,13 +2712,13 @@ static ssize_t mts_attr_store_dc_dout(struct device *dev, struct device_attribut return -ENODEV; } - if (!strcmp(attr->attr.name, "dc-dout0")) { + if (!strcmp(attr->attr.name, "dout0")) { bit = BIT(0); - } else if (!strcmp(attr->attr.name, "dc-dout1")) { + } else if (!strcmp(attr->attr.name, "dout1")) { bit = BIT(1); - } else if (!strcmp(attr->attr.name, "dc-dout2")) { + } else if (!strcmp(attr->attr.name, "dout2")) { bit = BIT(2); - } else if (!strcmp(attr->attr.name, "dc-dout3")) { + } else if (!strcmp(attr->attr.name, "dout3")) { bit = BIT(3); } else { log_error("dc dout attr does not exist"); @@ -2690,13 +2755,13 @@ static ssize_t mts_attr_show_dc_dout(struct device *dev, struct device_attribute return -ENODEV; } - if (!strcmp(attr->attr.name, "dc-dout0")) { + if (!strcmp(attr->attr.name, "dout0")) { bit = BIT(0); - } else if (!strcmp(attr->attr.name, "dc-dout1")) { + } else if (!strcmp(attr->attr.name, "dout1")) { bit = BIT(1); - } else if (!strcmp(attr->attr.name, "dc-dout2")) { + } else if (!strcmp(attr->attr.name, "dout2")) { bit = BIT(2); - } else if (!strcmp(attr->attr.name, "dc-dout3")) { + } else if (!strcmp(attr->attr.name, "dout3")) { bit = BIT(3); } else { log_error("dc dout attr does not exist"); @@ -2714,25 +2779,81 @@ static ssize_t mts_attr_show_dc_dout(struct device *dev, struct device_attribute static ssize_t mts_attr_show_dc_adc(struct device *dev, struct device_attribute *attr, char *buf) { - /* TODO: actually write this function */ - return sprintf(buf, "%lu\n", (unsigned long) 0); + 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, "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); -static DEVICE_ATTR_RO_MTS(dev_attr_dc_din3, "dc-din3", mts_attr_show_dc_din); -static DEVICE_ATTR_MTS(dev_attr_dc_dout0, "dc-dout0", mts_attr_show_dc_dout, mts_attr_store_dc_dout); -static DEVICE_ATTR_MTS(dev_attr_dc_dout1, "dc-dout1", mts_attr_show_dc_dout, mts_attr_store_dc_dout); -static DEVICE_ATTR_MTS(dev_attr_dc_dout2, "dc-dout2", mts_attr_show_dc_dout, mts_attr_store_dc_dout); -static DEVICE_ATTR_MTS(dev_attr_dc_dout3, "dc-dout3", mts_attr_show_dc_dout, mts_attr_store_dc_dout); -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 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, @@ -3226,6 +3347,50 @@ static struct spi_driver mts_spi_dc_din_driver = { .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; @@ -3463,7 +3628,7 @@ static int __init mts_io_init(void) switch(mts_dc_product_id) { case MTDC_GPIOB_0_0: - log_info("adding GPIO daughter card attributes"); + log_debug("adding GPIO daughter card attributes"); if (! mtr2_add_daughter_card_attributes()) { log_error("failed to add GPIO daughter card attributes"); goto error1; @@ -3471,20 +3636,27 @@ static int __init mts_io_init(void) log_info("successfully added GPIO daughter card attributes"); } - log_info("registering daughter card dout driver"); + 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_info("registering daughter card din driver"); + 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: @@ -3655,6 +3827,7 @@ static void __exit mts_io_exit(void) 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: @@ -3685,3 +3858,4 @@ 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"); |