summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--io-module/mts_io.c302
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");