static struct gpio_pin gpio_pins_mtr2_0_0[] = {
	{
		.name = "NETH_RST",
		.pin = {
			.gpio = AT91_PIN_PC6,
			.flags = GPIOF_OPEN_DRAIN | GPIOF_INIT_HIGH,
			.label = "eth-switch-enabled",
		},
	},
	{
		.name = "RADIO_RESET",
		.pin = {
			.gpio = AT91_PIN_PC5,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "radio-reset",
		},
	},
	{
		.name = "RADIO_RESET",
		.pin = {
			.gpio = AT91_PIN_PC5,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "radio-power",
		},
	},
	{
		.name = "DEVICE_RESET",
		.pin = {
			.gpio = AT91_PIN_PC4,
			.flags = GPIOF_IN,
			.label = "reset",
		},
		.active_low = 1,
	},
	{
		.name = "LS_LED",
		.pin = {
			.gpio = AT91_PIN_PA14,
#if LED_LS_CONTROLLABLE
			.flags = GPIOF_OUT_INIT_HIGH,
#else
			.flags = GPIOF_IN,
#endif
			.label = "led-ls",
		},
		.active_low = 1,
	},
	{
		.name = "STATUS_LED",
		.pin = {
			.gpio = AT91_PIN_PA24,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "led-status",
		},
		.active_low = 1,
	},
	{
		.name = "STATUS_LED",
		.pin = {
			.gpio = AT91_PIN_PA24,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "led-a",
		},
		.active_low = 1,
	},
	{
		.name = "LED7",
		.pin = {
			.gpio = AT91_PIN_PA25,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-cd",
		},
		.active_low = 1,
	},
	{
		.name = "LED7",
		.pin = {
			.gpio = AT91_PIN_PA25,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-c",
		},
		.active_low = 1,
	},
	{
		.name = "LED10",
		.pin = {
			.gpio = AT91_PIN_PA26,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-sig1",
		},
		.active_low = 1,
	},
	{
		.name = "LED10",
		.pin = {
			.gpio = AT91_PIN_PA26,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-d",
		},
		.active_low = 1,
	},
	{
		.name = "LED11",
		.pin = {
			.gpio = AT91_PIN_PA27,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-sig2",
		},
		.active_low = 1,
	},
	{
		.name = "LED11",
		.pin = {
			.gpio = AT91_PIN_PA27,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-e",
		},
		.active_low = 1,
	},
	{
		.name = "LED12",
		.pin = {
			.gpio = AT91_PIN_PA28,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-sig3",
		},
		.active_low = 1,
	},
	{
		.name = "LED12",
		.pin = {
			.gpio = AT91_PIN_PA28,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-f",
		},
		.active_low = 1,
	},
	{
		.name = "LED13",
		.pin = {
			.gpio = AT91_PIN_PA29,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-wifi",
		},
		.active_low = 1,
	},
	{
		.name = "LED13",
		.pin = {
			.gpio = AT91_PIN_PA29,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "led-b",
		},
		.active_low = 1,
	},
	{
		.name = "UART3_DTR",
		.pin = {
			.gpio = AT91_PIN_PC12,
			.flags = GPIOF_IN,
			.label = "extserial-dtr",
		},
		.active_low = 1,
	},
	{
		.name = "UART3_DSR",
		.pin = {
			.gpio = AT91_PIN_PC11,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "extserial-dsr",
		},
		.active_low = 1,
	},
	{
		.name = "UART3_DCD",
		.pin = {
			.gpio = AT91_PIN_PC10,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "extserial-dcd",
		},
		.active_low = 1,
	},
	{
		.name = "UART3_RI",
		.pin = {
			.gpio = AT91_PIN_PC13,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "extserial-ri",
		},
		.active_low = 1,
	},
	{
		.name = "NDC_RESET",
		.pin = {
			.gpio = AT91_PIN_PC3,
			.flags = GPIOF_OUT_INIT_HIGH,
			.label = "ndc-reset",
		},
	},
	{
		.name = "NDC_EEPROM_WRITE_PROTECT",
		.pin = {
			.gpio = AT91_PIN_PC26,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "ndc-eeprom-wp",
		},
	},
	{
		.name = "BT_EN",
		.pin = {
			.gpio = AT91_PIN_PD21,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "bt-enabled",
		},
	},
	{
		.name = "WLAN_EN",
		.pin = {
			.gpio = AT91_PIN_PC1,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "wlan-enabled",
		},
	},
	{
		.name = "SERIAL_MODE0",
		.pin = {
			.gpio = AT91_PIN_PC23,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "serial-mode",
		},
	},
	{
		.name = "SERIAL_MODE1",
		.pin = {
			.gpio = AT91_PIN_PC24,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "serial-mode",
		},
	},
	{
		.name = "SERIAL_MODE2",
		.pin = {
			.gpio = AT91_PIN_PC25,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "serial-mode",
		},
	},
	{
		.name = "RS4XX_TERM_RES",
		.pin = {
			.gpio = AT91_PIN_PC26,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "rs4xx-term-res",
		},
	},
	{
		.name = "NDC_GPIO1",
		.pin = {
			.gpio = AT91_PIN_PC0,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "dc-gpio1",
		},
	},
	{
		.name = "NDC_GPIO2",
		.pin = {
			.gpio = AT91_PIN_PC14,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "dc-gpio2",
		},
	},
	{
		.name = "NDC_GPIO3",
		.pin = {
			.gpio = AT91_PIN_PC29,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "dc-gpio3",
		},
	},
	{
		.name = "NDC_GPIO4",
		.pin = {
			.gpio = AT91_PIN_PC30,
			.flags = GPIOF_OUT_INIT_LOW,
			.label = "dc-gpio4",
		},
	},
	{
		.name = "NDC_INTERRUPT1",
		.pin = {
			.gpio = AT91_PIN_PC20,
			.flags = GPIOF_IN,
			.label = "dc-int1",
		},
	},
	{
		.name = "NDC_INTERRUPT2",
		.pin = {
			.gpio = AT91_PIN_PC21,
			.flags = GPIOF_IN,
			.label = "dc-int2",
		},
	},
	{ },
};

/* MTOCGD2 specific functions */
static ssize_t mts_attr_show_serial_mode(struct device *dev,
			struct device_attribute *attr,
			char *buf)
{
	int ret;
	int smode0;
	int smode1;
	int smode2;

	struct gpio_pin *pin_smode0 = gpio_pin_by_name("SERIAL_MODE0");
	struct gpio_pin *pin_smode1 = gpio_pin_by_name("SERIAL_MODE1");
	struct gpio_pin *pin_smode2 = gpio_pin_by_name("SERIAL_MODE2");

	if (!pin_smode0 || !pin_smode1 || !pin_smode2)
		return -ENODEV;

	mutex_lock(&mts_io_mutex);

	smode0 = gpio_get_value(pin_smode0->pin.gpio);
	smode1 = gpio_get_value(pin_smode1->pin.gpio);
	smode2 = gpio_get_value(pin_smode2->pin.gpio);

	if (smode2 == 0 && smode1 == 0 && smode0 == 1)
		ret = sprintf(buf, "rs232\n");
	else if (smode2 == 0 && smode1 == 1 && smode0 == 0)
		ret = sprintf(buf, "rs485\n");
	else if (smode2 == 1 && smode1 == 0 && smode0 == 0)
		ret = sprintf(buf, "rs422\n");
	else if (smode2 == 0 && smode1 == 0 && smode0 == 0)
		ret = sprintf(buf, "loopback\n");
	else
		ret = sprintf(buf, "error\n");

	mutex_unlock(&mts_io_mutex);

	return ret;
}

static ssize_t mts_attr_store_serial_mode(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int smode0;
	int smode1;
	int smode2;
	struct gpio_pin *pin_smode0 = gpio_pin_by_name("SERIAL_MODE0");
	struct gpio_pin *pin_smode1 = gpio_pin_by_name("SERIAL_MODE1");
	struct gpio_pin *pin_smode2 = gpio_pin_by_name("SERIAL_MODE2");

	if (!pin_smode0 || !pin_smode1 || !pin_smode2)
		return -ENODEV;

	if (!strcasecmp(buf, "rs232")) {
		smode2 = 0;
		smode1 = 0;
		smode0 = 1;
	}
	else if (!strcasecmp(buf, "rs485")) {
		smode2 = 0;
		smode1 = 1;
		smode0 = 0;
	}
	else if (!strcasecmp(buf, "rs422")) {
		smode2 = 1;
		smode1 = 0;
		smode0 = 0;
	}
	else if (!strcasecmp(buf, "loopback")) {
		smode2 = 0;
		smode1 = 0;
		smode0 = 0;
	}
	else  {
		return -EINVAL;
	}

	mutex_lock(&mts_io_mutex);

	gpio_set_value(pin_smode2->pin.gpio, smode2);
	gpio_set_value(pin_smode1->pin.gpio, smode1);
	gpio_set_value(pin_smode0->pin.gpio, smode0);

	mutex_unlock(&mts_io_mutex);

	return count;
}

/* MTOCGD2 specific attributes */
static DEVICE_ATTR_MTS(dev_attr_serial_mode, "serial-mode",
	mts_attr_show_serial_mode, mts_attr_store_serial_mode);
static DEVICE_ATTR_MTS(dev_attr_eth_switch_enabled, "eth-switch-enabled",
	mts_attr_show_gpio_pin, mts_attr_store_gpio_pin);
static DEVICE_ATTR_MTS(dev_attr_rs4xx_term_res, "rs4xx-term-res",
	mts_attr_show_gpio_pin, mts_attr_store_gpio_pin);

static struct attribute *mtr2_platform_attributes[] = {
	&dev_attr_vendor_id.attr,
	&dev_attr_product_id.attr,
	&dev_attr_device_id.attr,
	&dev_attr_hw_version.attr,
	&dev_attr_imei.attr,
	&dev_attr_eth_mac.attr,
	&dev_attr_wifi_mac.attr,
	&dev_attr_reset.attr,
	&dev_attr_reset_monitor.attr,
	&dev_attr_radio_power.attr,
	&dev_attr_radio_reset.attr,
	&dev_attr_ndc_reset.attr,
	&dev_attr_extserial_dtr.attr,
	&dev_attr_extserial_dsr_gpio.attr,
	&dev_attr_extserial_ri_gpio.attr,
	&dev_attr_extserial_dcd_gpio.attr,
	&dev_attr_eth_switch_enabled.attr,
	&dev_attr_bt_enabled.attr,
	&dev_attr_wlan_enabled.attr,

	&dev_attr_serial_mode.attr,
	&dev_attr_rs4xx_term_res.attr,

	&dev_attr_led_status.attr,
	&dev_attr_led_wifi_gpio.attr,
	&dev_attr_led_cd_gpio.attr,
	&dev_attr_led_sig1_gpio.attr,
	&dev_attr_led_sig2_gpio.attr,
	&dev_attr_led_sig3_gpio.attr,

	&dev_attr_led_a_gpio.attr,
	&dev_attr_led_b_gpio.attr,
	&dev_attr_led_c_gpio.attr,
	&dev_attr_led_d_gpio.attr,
	&dev_attr_led_e_gpio.attr,
	&dev_attr_led_f_gpio.attr,

	&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,
};

static bool mtr2_add_daughter_card_attributes(void)
{
	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_group mtr2_platform_attribute_group = {
	.attrs = mtr2_platform_attributes
};