/* * IO Controller for the Sparkcell Platform * * Copyright (C) 2010 by Multi-Tech Systems * * Author: James Maki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * See arch/arm/mach-at91board-sam9g20ek.c for an alternate approach to * setting LEDs (ek_leds) and adding platform devices and platform drivers. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mts_io.h" #define DRIVER_VERSION "v0.2.0" #define DRIVER_AUTHOR "James Maki " #define DRIVER_DESC "IO Controller for the SparkCell Platform" #define DRIVER_NAME "mts-io" #define PLATFORM_NAME "sparkcell" #if DEBUG # define dbg(fmt, args...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ##args) #else # define dbg(fmt, args...) do {} while (0) #endif #define error(fmt, args...) printk(KERN_ERR __FILE__ ": " fmt "\n" , ##args) #define info(fmt, args...) printk(KERN_INFO fmt "\n" , ##args) #define BOARD_REVA 0 #define BOARD_REVB 1 #define BOARD_REVC 2 #define LED_CD_BIT BIT(0) #define EXTSERIAL_RI_BIT BIT(1) #define EXTSERIAL_DSR_BIT BIT(2) #define CS0_BIT3 BIT(3) #define LED_SIG1_BIT BIT(4) #define LED_SIG2_BIT BIT(5) #define LED_SIG3_BIT BIT(6) #define EXTSERIAL_DCD_BIT BIT(7) #define GPIO_CS0 AT91_PIN_PB3 #define GPIO_CS1 AT91_PIN_PC5 #define GPIO_CS2 AT91_PIN_PC4 #define GPIO_CS3 AT91_PIN_PC3 #define GPIO_ENIO AT91_PIN_PC15 #define GPIO_ETH0_ENABLED AT91_PIN_PB31 #define GPIO_RADIO_RESET AT91_PIN_PB30 #define GPIO_OPTRST AT91_PIN_PA22 #define GPIO_LS_LED AT91_PIN_PC9 #define GPIO_SERCLK AT91_PIN_PB2 #define GPIO_SERDOUT AT91_PIN_PB1 #define GPIO_SERDIN AT91_PIN_PB0 #define GPIO_VER0 AT91_PIN_PA23 #define GPIO_VER1 AT91_PIN_PA24 #define GPIO_RSERSRC AT91_PIN_PC7 #define GPIO_DBSERON AT91_PIN_PC6 #define GPIO_DTR1 AT91_PIN_PC10 #define GPIO_RXD1MON AT91_PIN_PC8 #define GPIO_EXTIN0 AT91_PIN_PB13 #define GPIO_EXTIN1 AT91_PIN_PB12 #define GPIO_EXTIN2 AT91_PIN_PB11 #define GPIO_EXTIN3 AT91_PIN_PB10 #define GPIO_EXTIN4 AT91_PIN_PB9 #define GPIO_EXTIN5 AT91_PIN_PB8 #define GPIO_GPS_NINT2 AT91_PIN_PC2 #define GPIO_STATUS_LED AT91_PIN_PA30 #define LED_STATUS_CONTROLLABLE 1 #define LED_LS_CONTROLLABLE 0 enum { LED_OFF, LED_ON, LED_FLASHING, }; static u8 board_rev = BOARD_REVA; static u8 cs0_bits = 0xFF; static DEFINE_MUTEX(mts_io_mutex); #if LED_STATUS_CONTROLLABLE static int led_mode_status = LED_OFF; #endif static pid_t reset_pid = -1; static pid_t reset_count = 0; static int reset_short_signal = SIGUSR1; static int reset_long_signal = SIGUSR2; #define BLINK_PER_SEC 8 #define BLINK_INTERVAL (HZ / BLINK_PER_SEC) #define RESET_HOLD_COUNT (BLINK_PER_SEC * 3) static void blink_callback(struct work_struct *ignored); static DECLARE_DELAYED_WORK(blink_work, blink_callback); static void blink_callback(struct work_struct *ignored) { unsigned long reset_pressed = !at91_get_gpio_value(GPIO_OPTRST); struct pid *vpid = NULL; mutex_lock(&mts_io_mutex); if (reset_pid > 0) { vpid = find_vpid(reset_pid); } if (vpid) { if (reset_pressed) { reset_count++; } else if (reset_count > 0 && reset_count < RESET_HOLD_COUNT) { kill_pid(vpid, reset_short_signal, 1); reset_count = 0; } if (reset_count >= RESET_HOLD_COUNT) { reset_count = 0; kill_pid(vpid, reset_long_signal, 1); } } else { reset_count = 0; } #if LED_STATUS_CONTROLLABLE if (led_mode_status == LED_FLASHING) { at91_set_gpio_value(GPIO_STATUS_LED, !at91_get_gpio_value(GPIO_STATUS_LED)); } #endif mutex_unlock(&mts_io_mutex); schedule_delayed_work(&blink_work, BLINK_INTERVAL); } static void serial_writeb(u8 data, int cs) { int i; if (board_rev == BOARD_REVA) { if (cs == GPIO_CS0) { cs = 2; } else if (cs == GPIO_CS1) { cs = 3; } else if (cs == GPIO_CS2) { cs = 4; } else if (cs == GPIO_CS3) { cs = 5; } else { return; } at91_set_gpio_value(GPIO_CS0, cs & 1); at91_set_gpio_value(GPIO_CS1, cs & 2); at91_set_gpio_value(GPIO_CS2, cs & 4); } else { at91_set_gpio_value(cs, 0); } for (i = 7; i >= 0; i--) { at91_set_gpio_value(GPIO_SERDOUT, data & (1 << i)); at91_set_gpio_value(GPIO_SERCLK, 1); at91_set_gpio_value(GPIO_SERCLK, 0); } if (board_rev == BOARD_REVA) { at91_set_gpio_value(GPIO_CS0, 1); at91_set_gpio_value(GPIO_CS1, 1); at91_set_gpio_value(GPIO_CS2, 1); } else { at91_set_gpio_value(cs, 1); } } static u16 serial_readw(int cs) { int i; u16 data; at91_set_gpio_value(GPIO_SERCLK, 1); /* set low so we don't power down temp sensor */ at91_set_gpio_value(GPIO_SERDOUT, 0); if (board_rev == BOARD_REVA) { if (cs == GPIO_CS0) { cs = 2; } else if (cs == GPIO_CS1) { cs = 3; } else if (cs == GPIO_CS2) { cs = 4; } else if (cs == GPIO_CS3) { cs = 5; } else { cs = 2; } at91_set_gpio_value(GPIO_CS0, cs & 1); at91_set_gpio_value(GPIO_CS1, cs & 2); at91_set_gpio_value(GPIO_CS2, cs & 4); } else { at91_set_gpio_value(cs, 0); } data = 0; for (i = 15; i >= 0; i--) { at91_set_gpio_value(GPIO_SERCLK, 0); at91_set_gpio_value(GPIO_SERCLK, 1); data |= (((u16) at91_get_gpio_value(GPIO_SERDIN)) << i); } if (board_rev == BOARD_REVA) { at91_set_gpio_value(GPIO_CS0, 1); at91_set_gpio_value(GPIO_CS1, 1); at91_set_gpio_value(GPIO_CS2, 1); } else { at91_set_gpio_value(cs, 1); } at91_set_gpio_value(GPIO_SERCLK, 0); return data; } static int radio_reset(void) { int ret; ret = at91_set_gpio_value(GPIO_RADIO_RESET, 0); if (ret) { return ret; } udelay(1000); ret = at91_set_gpio_value(GPIO_RADIO_RESET, 1); return ret; } static int board_temperature(void) { int temp; temp = serial_readw(GPIO_CS2); /* * If sign bit set, convert raw value to negative integer. * @see: ADT7302 datasheet */ if (temp & 0x2000) { temp = temp - 16384; } temp = temp / 32 + 1 * ((temp % 32) >= 16); return temp; } static ssize_t show_radio_reset(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = at91_get_gpio_value(GPIO_RADIO_RESET); mutex_unlock(&mts_io_mutex); if (value < 0) { return value; } return sprintf(buf, "%d\n", value); } static ssize_t store_radio_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; int err; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } if (value != 0) { return -EINVAL; } mutex_lock(&mts_io_mutex); err = radio_reset(); mutex_unlock(&mts_io_mutex); if (err) { return err; } return count; } static struct device_attribute dev_attr_radio_reset = { .attr = { .name = "radio-reset", .mode = 0644, }, .show = show_radio_reset, .store = store_radio_reset, }; static ssize_t show_eth0_enabled(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = at91_get_gpio_value(GPIO_ETH0_ENABLED); mutex_unlock(&mts_io_mutex); if (value < 0) { return value; } return sprintf(buf, "%d\n", value); } static ssize_t store_eth0_enabled(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; int err; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); err = at91_set_gpio_value(GPIO_ETH0_ENABLED, value); mutex_unlock(&mts_io_mutex); if (err) { return err; } return count; } static struct device_attribute dev_attr_eth0_enabled = { .attr = { .name = "eth0-enabled", .mode = 0644, }, .show = show_eth0_enabled, .store = store_eth0_enabled, }; static ssize_t show_extserial_dcd(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !(cs0_bits & EXTSERIAL_DCD_BIT); mutex_unlock(&mts_io_mutex); return sprintf(buf, "%d\n", value); } static ssize_t store_extserial_dcd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); if (value) { cs0_bits &= ~EXTSERIAL_DCD_BIT; } else { cs0_bits |= EXTSERIAL_DCD_BIT; } serial_writeb(cs0_bits, GPIO_CS0); mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_extserial_dcd = { .attr = { .name = "extserial-dcd", .mode = 0644, }, .show = show_extserial_dcd, .store = store_extserial_dcd, }; static ssize_t show_extserial_ri(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !(cs0_bits & EXTSERIAL_RI_BIT); mutex_unlock(&mts_io_mutex); return sprintf(buf, "%d\n", value); } static ssize_t store_extserial_ri(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); if (value) { cs0_bits &= ~EXTSERIAL_RI_BIT; } else { cs0_bits |= EXTSERIAL_RI_BIT; } serial_writeb(cs0_bits, GPIO_CS0); mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_extserial_ri = { .attr = { .name = "extserial-ri", .mode = 0644, }, .show = show_extserial_ri, .store = store_extserial_ri, }; static ssize_t show_extserial_dsr(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !(cs0_bits & EXTSERIAL_DSR_BIT); mutex_unlock(&mts_io_mutex); return sprintf(buf, "%d\n", value); } static ssize_t store_extserial_dsr(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); if (value) { cs0_bits &= ~EXTSERIAL_DSR_BIT; } else { cs0_bits |= EXTSERIAL_DSR_BIT; } serial_writeb(cs0_bits, GPIO_CS0); mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_extserial_dsr = { .attr = { .name = "extserial-dsr", .mode = 0644, }, .show = show_extserial_dsr, .store = store_extserial_dsr, }; static ssize_t show_led_sig1(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !(cs0_bits & LED_SIG1_BIT); mutex_unlock(&mts_io_mutex); return sprintf(buf, "%d\n", value); } static ssize_t store_led_sig1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); if (value) { cs0_bits &= ~LED_SIG1_BIT; } else { cs0_bits |= LED_SIG1_BIT; } serial_writeb(cs0_bits, GPIO_CS0); mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_led_sig1 = { .attr = { .name = "led-sig1", .mode = 0644, }, .show = show_led_sig1, .store = store_led_sig1, }; static struct device_attribute dev_attr_led_sdk_c = { .attr = { .name = "led-sdk-c", .mode = 0644, }, .show = show_led_sig1, .store = store_led_sig1, }; static ssize_t show_led_sig2(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !(cs0_bits & LED_SIG2_BIT); mutex_unlock(&mts_io_mutex); return sprintf(buf, "%d\n", value); } static ssize_t store_led_sig2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); if (value) { cs0_bits &= ~LED_SIG2_BIT; } else { cs0_bits |= LED_SIG2_BIT; } serial_writeb(cs0_bits, GPIO_CS0); mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_led_sig2 = { .attr = { .name = "led-sig2", .mode = 0644, }, .show = show_led_sig2, .store = store_led_sig2, }; static struct device_attribute dev_attr_led_sdk_d = { .attr = { .name = "led-sdk-d", .mode = 0644, }, .show = show_led_sig2, .store = store_led_sig2, }; static ssize_t show_led_sig3(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !(cs0_bits & LED_SIG3_BIT); mutex_unlock(&mts_io_mutex); return sprintf(buf, "%d\n", value); } static ssize_t store_led_sig3(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); if (value) { cs0_bits &= ~LED_SIG3_BIT; } else { cs0_bits |= LED_SIG3_BIT; } serial_writeb(cs0_bits, GPIO_CS0); mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_led_sig3 = { .attr = { .name = "led-sig3", .mode = 0644, }, .show = show_led_sig3, .store = store_led_sig3, }; static struct device_attribute dev_attr_led_sdk_e = { .attr = { .name = "led-sdk-e", .mode = 0644, }, .show = show_led_sig3, .store = store_led_sig3, }; static ssize_t show_led_cd(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !(cs0_bits & LED_CD_BIT); mutex_unlock(&mts_io_mutex); return sprintf(buf, "%d\n", value); } static ssize_t store_led_cd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); if (value) { cs0_bits &= ~LED_CD_BIT; } else { cs0_bits |= LED_CD_BIT; } serial_writeb(cs0_bits, GPIO_CS0); mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_led_cd = { .attr = { .name = "led-cd", .mode = 0644, }, .show = show_led_cd, .store = store_led_cd, }; static struct device_attribute dev_attr_led_sdk_b = { .attr = { .name = "led-sdk-b", .mode = 0644, }, .show = show_led_cd, .store = store_led_cd, }; #if LED_STATUS_CONTROLLABLE static ssize_t show_led_status(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", led_mode_status); } static ssize_t store_led_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; int ret; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); switch (value) { case LED_OFF: led_mode_status = LED_OFF; ret = at91_set_gpio_value(GPIO_STATUS_LED, 1); break; case LED_ON: led_mode_status = LED_ON; ret = at91_set_gpio_value(GPIO_STATUS_LED, 0); break; case LED_FLASHING: led_mode_status = LED_FLASHING; ret = at91_set_gpio_value(GPIO_STATUS_LED, 0); break; default: ret = -EINVAL; } mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_led_status = { .attr = { .name = "led-status", .mode = 0644, }, .show = show_led_status, .store = store_led_status, }; static struct device_attribute dev_attr_led_sdk_a = { .attr = { .name = "led-sdk-a", .mode = 0644, }, .show = show_led_status, .store = store_led_status, }; #endif #if LED_LS_CONTROLLABLE static ssize_t show_led_ls(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = at91_get_gpio_value(GPIO_LS_LED); mutex_unlock(&mts_io_mutex); if (value < 0) { return value; } return sprintf(buf, "%d\n", !value); } static ssize_t store_led_ls(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; int err; if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } mutex_lock(&mts_io_mutex); err = at91_set_gpio_value(GPIO_LS_LED, !value); mutex_unlock(&mts_io_mutex); if (err) { return err; } return count; } static struct device_attribute dev_attr_led_ls = { .attr = { .name = "led-ls", .mode = 0644, }, .show = show_led_ls, .store = store_led_ls, }; #endif static ssize_t show_reset(struct device *dev, struct device_attribute *attr, char *buf) { int value; mutex_lock(&mts_io_mutex); value = !at91_get_gpio_value(GPIO_OPTRST); mutex_unlock(&mts_io_mutex); if (value < 0) { return value; } return sprintf(buf, "%d\n", value); } static struct device_attribute dev_attr_reset = { .attr = { .name = "reset", .mode = 0444, }, .show = show_reset, }; static ssize_t show_reset_monitor(struct device *dev, struct device_attribute *attr, char *buf) { int ret; mutex_lock(&mts_io_mutex); ret = sprintf(buf, "%d %d %d\n", reset_pid, reset_short_signal, reset_long_signal); mutex_unlock(&mts_io_mutex); return ret; } static ssize_t store_reset_monitor(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { pid_t pid; int short_signal; int long_signal; if (sscanf(buf, "%i %i %i", &pid, &short_signal, &long_signal) != 3) { return -EINVAL; } mutex_lock(&mts_io_mutex); reset_pid = pid; reset_short_signal = short_signal; reset_long_signal = long_signal; mutex_unlock(&mts_io_mutex); return count; } static struct device_attribute dev_attr_reset_monitor = { .attr = { .name = "reset-monitor", .mode = 0644, }, .show = show_reset_monitor, .store = store_reset_monitor, }; static ssize_t show_board_temperature(struct device *dev, struct device_attribute *attr, char *buf) { int ret; mutex_lock(&mts_io_mutex); ret = sprintf(buf, "%d\n", board_temperature()); mutex_unlock(&mts_io_mutex); return ret; } static struct device_attribute dev_attr_board_temperature = { .attr = { .name = "board-temperature", .mode = 0444, }, .show = show_board_temperature, }; static struct attribute *platform_attributes[] = { &dev_attr_radio_reset.attr, &dev_attr_eth0_enabled.attr, &dev_attr_extserial_dcd.attr, &dev_attr_extserial_ri.attr, &dev_attr_led_sig1.attr, &dev_attr_led_sdk_c.attr, &dev_attr_led_sig2.attr, &dev_attr_led_sdk_d.attr, &dev_attr_led_sig3.attr, &dev_attr_led_sdk_e.attr, &dev_attr_led_cd.attr, &dev_attr_led_sdk_b.attr, #if LED_STATUS_CONTROLLABLE &dev_attr_led_status.attr, &dev_attr_led_sdk_a.attr, #endif #if LED_LS_CONTROLLABLE &dev_attr_led_ls.attr, #endif &dev_attr_reset.attr, &dev_attr_reset_monitor.attr, &dev_attr_board_temperature.attr, NULL, }; static struct attribute_group platform_attribute_group = { .attrs = platform_attributes }; static struct platform_device *mts_io_platform_device; enum { DIR_INPUT, DIR_OUTPUT, }; struct gpio_pin_init { char name[32]; unsigned long pin; int direction; int output_value; int use_pullup; int board_rev_added; }; static struct gpio_pin_init init_pins[] = { /* * GPIO_{VER0,VER1} need to be first in the list. */ { .name = "GPIO_VER0", .pin = GPIO_VER0, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_VER1", .pin = GPIO_VER1, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_CS0", .pin = GPIO_CS0, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 1, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_CS1", .pin = GPIO_CS1, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 1, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_CS2", .pin = GPIO_CS2, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 1, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_CS3", .pin = GPIO_CS3, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 1, .board_rev_added = BOARD_REVC, }, { .name = "GPIO_ENIO", .pin = GPIO_ENIO, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_ETH0_ENABLED", .pin = AT91_PIN_PB31, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_RADIO_RESET", .pin = GPIO_RADIO_RESET, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_OPTRST", .pin = GPIO_OPTRST, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, #if LED_LS_CONTROLLABLE { .name = "GPIO_LS_LED", .pin = GPIO_LS_LED, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, #endif { .name = "GPIO_SERCLK", .pin = GPIO_SERCLK, .direction = DIR_OUTPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_SERDOUT", .pin = GPIO_SERDOUT, .direction = DIR_OUTPUT, .output_value = 0, .use_pullup = 1, .board_rev_added = BOARD_REVA, }, { .name = "GPIO_SERDIN", .pin = GPIO_SERDIN, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 1, .board_rev_added = BOARD_REVA, }, #if LED_STATUS_CONTROLLABLE { .name = "GPIO_STATUS_LED", .pin = GPIO_STATUS_LED, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 0, .board_rev_added = BOARD_REVA, }, #endif { .name = "GPIO_RSERSRC", .pin = GPIO_RSERSRC, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 0, .board_rev_added = BOARD_REVB, }, { .name = "GPIO_DBSERON", .pin = GPIO_DBSERON, .direction = DIR_OUTPUT, .output_value = 1, .use_pullup = 0, .board_rev_added = BOARD_REVB, }, { .name = "GPIO_DTR1", .pin = GPIO_DTR1, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVB, }, { .name = "GPIO_RXD1MON", .pin = GPIO_RXD1MON, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVB, }, { .name = "GPIO_EXTIN0", .pin = GPIO_EXTIN0, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVB, }, { .name = "GPIO_EXTIN1", .pin = GPIO_EXTIN1, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVB, }, { .name = "GPIO_EXTIN2", .pin = GPIO_EXTIN2, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVB, }, #if 0 { .name = "GPIO_EXTIN3", .pin = GPIO_EXTIN3, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVC, }, { .name = "GPIO_EXTIN4", .pin = GPIO_EXTIN4, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVC, }, { .name = "GPIO_EXTIN5", .pin = GPIO_EXTIN5, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVC, }, { .name = "GPIO_GPS_NINT2", .pin = GPIO_GPS_NINT2, .direction = DIR_INPUT, .output_value = 0, .use_pullup = 0, .board_rev_added = BOARD_REVC, }, #endif }; static int __init mts_io_init(void) { int i; int ret; info(DRIVER_NAME ": init"); mts_io_platform_device = platform_device_alloc(PLATFORM_NAME, -1); if (!mts_io_platform_device) { ret = -ENOMEM; goto error_platform_device_alloc; } ret = platform_device_add(mts_io_platform_device); if (ret) { goto error_platform_device_add; } ret = sysfs_create_group(&mts_io_platform_device->dev.kobj, &platform_attribute_group); if (ret) { goto error_sysfs_create_group; } for (i = 0; i < ARRAY_SIZE(init_pins); i++) { gpio_request(init_pins[i].pin, init_pins[i].name); if (board_rev >= init_pins[i].board_rev_added) { if (init_pins[i].direction == DIR_OUTPUT) { at91_set_gpio_output(init_pins[i].pin, init_pins[i].output_value); } else { at91_set_gpio_input(init_pins[i].pin, init_pins[i].use_pullup); } } if (i == 1) { board_rev = (at91_get_gpio_value(GPIO_VER1) << 1) | at91_get_gpio_value(GPIO_VER0); board_rev ^= 0x03; info(DRIVER_NAME ": board rev: %d", board_rev); } } serial_writeb(cs0_bits, GPIO_CS0); serial_writeb(0xFF, GPIO_CS1); /* * enable serial device data output bus */ at91_set_gpio_value(GPIO_ENIO, 0); blink_callback(NULL); return 0; error_sysfs_create_group: platform_device_del(mts_io_platform_device); error_platform_device_add: platform_device_put(mts_io_platform_device); error_platform_device_alloc: error(DRIVER_NAME " init failed: %d", ret); return ret; } static void __exit mts_io_exit(void) { int i; cancel_delayed_work_sync(&blink_work); if (board_rev >= init_pins[i].board_rev_added) { for (i = 0; i < ARRAY_SIZE(init_pins); i++) { at91_set_gpio_input(init_pins[i].pin, init_pins[i].use_pullup); } } sysfs_remove_group(&mts_io_platform_device->dev.kobj, &platform_attribute_group); platform_device_unregister(mts_io_platform_device); info(DRIVER_NAME ": exiting"); } module_init(mts_io_init); module_exit(mts_io_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL");