diff options
Diffstat (limited to 'recipes-kernel/linux/linux-yocto-3.10/h3600/0001-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3xxx.patch')
-rw-r--r-- | recipes-kernel/linux/linux-yocto-3.10/h3600/0001-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3xxx.patch | 527 |
1 files changed, 0 insertions, 527 deletions
diff --git a/recipes-kernel/linux/linux-yocto-3.10/h3600/0001-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3xxx.patch b/recipes-kernel/linux/linux-yocto-3.10/h3600/0001-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3xxx.patch deleted file mode 100644 index e056605..0000000 --- a/recipes-kernel/linux/linux-yocto-3.10/h3600/0001-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3xxx.patch +++ /dev/null @@ -1,527 +0,0 @@ -From a843ffb026e18e8912167692119ffe1298e81f7e Mon Sep 17 00:00:00 2001 -From: Dmitry Artamonow <mad_soft@inbox.ru> -Date: Sat, 21 Mar 2009 16:06:56 +0300 -Subject: [PATCH 1/7] MFD: driver for Atmel Microcontroller on iPaq h3xxx - -This adds a driver for the Atmel Microcontroller found on the -iPAQ h3xxx series. This device handles some keys, the -touchscreen, and the battery monitoring. - -This is a port of a driver from handhelds.org 2.6.21 kernel, -written by Alessandro GARDICH. It has been heavily cleaned and -converted to mfd-core by Dmitry Artamonow and rewritten -again for the v3.x series kernels by Linus Walleij. - -Signed-off-by: Alessandro GARDICH <gremlin@gremlin.it> -Signed-off-by: Dmitry Artamonow <mad_soft@inbox.ru> -Signed-off-by: Linus Walleij <linus.walleij@linaro.org> ---- - drivers/mfd/Kconfig | 10 ++ - drivers/mfd/Makefile | 1 + - drivers/mfd/ipaq-micro.c | 383 +++++++++++++++++++++++++++++++++++++++++ - include/linux/mfd/ipaq-micro.h | 73 ++++++++ - 4 files changed, 467 insertions(+) - create mode 100644 drivers/mfd/ipaq-micro.c - create mode 100644 include/linux/mfd/ipaq-micro.h - -diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index d54e985748b7..38db97060c4a 100644 ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -223,6 +223,16 @@ config MFD_INTEL_MSIC - Passage) chip. This chip embeds audio, battery, GPIO, etc. - devices used in Intel Medfield platforms. - -+config MFD_IPAQ_MICRO -+ bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" -+ depends on SA1100_H3100 || SA1100_H3600 -+ select MFD_CORE -+ help -+ Select this to get support for the Microcontroller found in -+ the Compaq iPAQ handheld computers. This is an Atmel -+ AT90LS8535 microcontroller flashed with a special iPAQ -+ firmware using the custom protocol implemented in this driver. -+ - config MFD_JANZ_CMODIO - tristate "Janz CMOD-IO PCI MODULbus Carrier Board" - select MFD_CORE -diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index 718e94a2a9a7..4fddef75bdad 100644 ---- a/drivers/mfd/Makefile -+++ b/drivers/mfd/Makefile -@@ -155,3 +155,4 @@ obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o - obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o - obj-$(CONFIG_MFD_RETU) += retu-mfd.o - obj-$(CONFIG_MFD_AS3711) += as3711.o -+obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o -diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c -new file mode 100644 -index 000000000000..92deae2114e1 ---- /dev/null -+++ b/drivers/mfd/ipaq-micro.c -@@ -0,0 +1,383 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * h3xxx Atmel microcontroller companion support -+ * -+ * This is an Atmel AT90LS8535 with a special flashed-in firmware that -+ * implements the special protocol used by this driver. -+ * -+ * based on previous kernel 2.4 version by Andrew Christian -+ * Author : Alessandro Gardich <gremlin@gremlin.it> -+ * Author : Dmitry Artamonow <mad_soft@inbox.ru> -+ * Author : Linus Walleij <linus.walleij@linaro.org> -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/pm.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+#include <linux/mfd/core.h> -+#include <linux/mfd/ipaq-micro.h> -+ -+#include <mach/hardware.h> -+ -+static void micro_rx_msg(struct ipaq_micro *micro, int id, int len, u8 *data) -+{ -+ int i; -+ -+ spin_lock(µ->lock); -+ switch (id) { -+ case MSG_VERSION: -+ if (len == 4) { -+ memcpy(micro->version, data, 4); -+ micro->version[4] = '\0'; -+ } else if (len == 9) { -+ memcpy(micro->version, data, 4); -+ micro->version[4] = '\0'; -+ /* Bytes 4-7 are "pack", byte 8 is "boot type" */ -+ } else { -+ dev_err(micro->dev, -+ "illegal version message %d bytes\n", len); -+ } -+ break; -+ case MSG_BACKLIGHT: -+ /* empty ack, just ignore */ -+ break; -+ case MSG_KEYBOARD: -+ if (micro->h_key != NULL) -+ micro->h_key(len, data); -+ else -+ dev_err(micro->dev, "ipaq micro : key message ignored, " -+ "no handle \n"); -+ break; -+ case MSG_TOUCHSCREEN: -+ if (micro->h_ts != NULL) -+ micro->h_ts(len, data); -+ else -+ dev_err(micro->dev, "ipaq micro : touchscreen message" -+ " ignored, no handle \n"); -+ break; -+ case MSG_THERMAL_SENSOR: -+ if (micro->h_temp != NULL) -+ micro->h_temp(len, data); -+ else -+ dev_err(micro->dev, "ipaq micro : temperature message" -+ " ignored, no handle \n"); -+ break; -+ case MSG_NOTIFY_LED: -+ /* Empty ack, just ignore */ -+ break; -+ case MSG_BATTERY: -+ if (micro->h_batt != NULL) -+ micro->h_batt(len, data); -+ else -+ dev_err(micro->dev, "ipaq micro : battery message" -+ " ignored, no handle \n"); -+ break; -+ default: -+ dev_err(micro->dev, -+ "ipaq micro : unknown msg %d [%d] ", id, len); -+ for (i = 0; i < len; ++i) -+ pr_cont("0x%02x ", data[i]); -+ pr_cont("\n"); -+ } -+ complete(µ->msg_ack); -+ spin_unlock(µ->lock); -+} -+ -+static void micro_process_char(struct ipaq_micro *micro, u8 ch) -+{ -+ struct ipaq_micro_rxdev *rx = µ->rx; -+ -+ switch (rx->state) { -+ case STATE_SOF: /* Looking for SOF */ -+ if (ch == CHAR_SOF) -+ rx->state = STATE_ID; /* Next byte is the id and len */ -+ break; -+ case STATE_ID: /* Looking for id and len byte */ -+ rx->id = (ch & 0xf0) >> 4 ; -+ rx->len = (ch & 0x0f); -+ rx->index = 0; -+ rx->chksum = ch; -+ rx->state = (rx->len > 0) ? STATE_DATA : STATE_CHKSUM; -+ break; -+ case STATE_DATA: /* Looking for 'len' data bytes */ -+ rx->chksum += ch; -+ rx->buf[rx->index] = ch; -+ if (++rx->index == rx->len) -+ rx->state = STATE_CHKSUM; -+ break; -+ case STATE_CHKSUM: /* Looking for the checksum */ -+ if (ch == rx->chksum) -+ micro_rx_msg(micro, rx->id, rx->len, rx->buf); -+ rx->state = STATE_SOF; -+ break; -+ } -+} -+ -+static void micro_rx_chars(struct ipaq_micro *micro) -+{ -+ unsigned int status, ch; -+ -+ while ((status = Ser1UTSR1) & UTSR1_RNE) { -+ ch = Ser1UTDR; -+ if (status & UTSR1_PRE) -+ dev_err(micro->dev, "ipaq micro_rx : parity error\n"); -+ else if (status & UTSR1_FRE) -+ dev_err(micro->dev, "ipaq micro_rx : framing error\n"); -+ else if (status & UTSR1_ROR) -+ dev_err(micro->dev, "ipaq micro_rx : overrun error\n"); -+ micro_process_char(micro, ch); -+ } -+} -+ -+int ipaq_micro_tx_msg(struct ipaq_micro *micro, unsigned char id, -+ unsigned char len, unsigned char *data) -+{ -+ struct ipaq_micro_txdev *tx = µ->tx; -+ int free_space; -+ int i; -+ u8 checksum; -+ int head, tail; -+ -+ /* After TX, an interrupt will be triggered that completes */ -+ init_completion(µ->msg_ack); -+ -+ tail = atomic_read(&tx->tail); -+ head = atomic_read(&tx->head); -+ -+ free_space = (head >= tail) ? (TX_BUF_SIZE - head + tail - 1) \ -+ : (tail - head - 1); -+ -+ if (free_space < len + 2) { -+ dev_err(micro->dev, "%s : no avaiable space on tx buffer.", -+ __func__); -+ return -EIO; -+ } -+ -+ tx->buf[head] = (u8) CHAR_SOF; -+ head = ((head+1) % TX_BUF_SIZE); -+ -+ checksum = ((id & 0x0f) << 4) | (len & 0x0f); -+ tx->buf[head] = checksum; -+ head = ((head+1) % TX_BUF_SIZE); -+ -+ for (i = 0; i < len; ++i) { -+ tx->buf[head] = data[i]; -+ head = ((head + 1) % TX_BUF_SIZE); -+ checksum += data[i]; -+ } -+ -+ tx->buf[head] = checksum; -+ head = ((head + 1) % TX_BUF_SIZE); -+ -+ atomic_set(&tx->head, head); -+ -+ Ser1UTCR3 |= UTCR3_TIE; /* enable interrupt */ -+ -+ return 0; -+} -+EXPORT_SYMBOL(ipaq_micro_tx_msg); -+ -+static void ipaq_micro_get_version(struct ipaq_micro *micro) -+{ -+ ipaq_micro_tx_msg(micro, MSG_VERSION, 0, NULL); -+ wait_for_completion(µ->msg_ack); -+} -+ -+static void ipaq_micro_eeprom_read(struct ipaq_micro *micro, -+ u16 address, u8 *data, u16 len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++) { -+ u8 data[2]; -+ u16 read_sz = len - i; -+ -+ data[0] = 0; -+ -+ ipaq_micro_tx_msg(micro, MSG_EEPROM_READ, 2, NULL); -+ } -+} -+ -+static void micro_tx_chars(struct ipaq_micro *micro) -+{ -+ struct ipaq_micro_txdev *tx = µ->tx; -+ int head, tail; -+ -+ head = atomic_read(&tx->head); -+ tail = atomic_read(&tx->tail); -+ -+ while ((head != tail) && (Ser1UTSR1 & UTSR1_TNF)) { -+ Ser1UTDR = tx->buf[tail]; -+ tail = ((tail+1) % TX_BUF_SIZE); -+ } -+ atomic_set(&tx->tail, tail); -+ -+ if (tail == head) /* Stop interrupts */ -+ Ser1UTCR3 &= ~UTCR3_TIE; -+} -+ -+static void micro_reset_comm(struct ipaq_micro *micro) -+{ -+ struct ipaq_micro_rxdev *rx = µ->rx; -+ struct ipaq_micro_txdev *tx = µ->tx; -+ -+ /* Initialize Serial channel protocol frame */ -+ rx->state = STATE_SOF; /* Reset the state machine */ -+ -+ atomic_set(&tx->head, 0); -+ atomic_set(&tx->tail, 0); -+ -+ /* Set up interrupts */ -+ Ser1SDCR0 = 0x1; /* Select UART mode */ -+ -+ Ser1UTCR3 = 0; /* Clean up CR3 */ -+ Ser1UTCR0 = UTCR0_8BitData | UTCR0_1StpBit; /* Format: 8N1 */ -+ Ser1UTCR1 = 0; /* Baud rate: 115200 */ -+ Ser1UTCR2 = 0x1; -+ -+ Ser1UTSR0 = 0xff; /* Clear SR0 */ -+ Ser1UTCR3 = UTCR3_TXE | UTCR3_RXE | UTCR3_RIE; /* Enable RX int */ -+ Ser1UTCR3 &= ~UTCR3_TIE; /* Disable TX int */ -+} -+ -+static irqreturn_t micro_serial_isr(int irq, void *dev_id) -+{ -+ struct ipaq_micro *micro = dev_id; -+ struct ipaq_micro_txdev *tx = µ->tx; -+ unsigned int status; /* UTSR0 */ -+ int head, tail; -+ -+ status = Ser1UTSR0; -+ do { -+ if (status & (UTSR0_RID | UTSR0_RFS)) { -+ if (status & UTSR0_RID) -+ /* Clear the Receiver IDLE bit */ -+ Ser1UTSR0 = UTSR0_RID; -+ micro_rx_chars(micro); -+ } -+ -+ /* Clear break bits */ -+ if (status & (UTSR0_RBB | UTSR0_REB)) -+ Ser1UTSR0 = status & (UTSR0_RBB | UTSR0_REB); -+ -+ if (status & UTSR0_TFS) -+ micro_tx_chars(micro); -+ -+ status = Ser1UTSR0; -+ -+ head = atomic_read(&tx->head); -+ tail = atomic_read(&tx->tail); -+ } while (((head != tail) && (status & UTSR0_TFS)) || -+ status & (UTSR0_RFS | UTSR0_RID)); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct mfd_cell micro_cells[] = { -+ { -+ .name = "ipaq-micro-backlight", -+ }, -+ { -+ .name = "ipaq-micro-battery", -+ }, -+ { -+ .name = "ipaq-micro-keys", -+ }, -+ { -+ .name = "ipaq-micro-ts", -+ }, -+ { -+ .name = "ipaq-micro-leds", -+ }, -+}; -+ -+static int micro_suspend(struct device *dev) -+{ -+ /* __micro_backlight_set_power(FB_BLANK_POWERDOWN); // FIXME */ -+ return 0; -+} -+ -+static int micro_resume(struct device *dev) -+{ -+ struct ipaq_micro *micro = dev_get_drvdata(dev); -+ -+ micro_reset_comm(micro); -+ mdelay(10); -+ -+ return 0; -+} -+ -+static int micro_probe(struct platform_device *pdev) -+{ -+ struct ipaq_micro *micro; -+ int res = 0; -+ int irq; -+ -+ micro = devm_kzalloc(&pdev->dev, sizeof(*micro), GFP_KERNEL); -+ if (!micro) -+ return -ENOMEM; -+ micro->dev = &pdev->dev; -+ micro_reset_comm(micro); -+ irq = platform_get_irq(pdev, 0); -+ if (!irq) -+ return -EINVAL; -+ res = devm_request_irq(&pdev->dev, irq, micro_serial_isr, -+ IRQF_SHARED, "ipaq-micro", -+ micro); -+ if (res) { -+ dev_err(&pdev->dev, "%s: unable to grab serial port IRQ\n", -+ __func__); -+ return res; -+ } else -+ dev_info(&pdev->dev, "grabbed serial port IRQ\n"); -+ -+ -+ spin_lock_init(µ->lock); -+ platform_set_drvdata(pdev, micro); -+ -+ res = mfd_add_devices(&pdev->dev, pdev->id, micro_cells, -+ ARRAY_SIZE(micro_cells), NULL, 0, NULL); -+ if (res) { -+ dev_err(&pdev->dev, "error adding MFD cells"); -+ return res; -+ } -+ /* Check version */ -+ ipaq_micro_get_version(micro); -+ dev_info(&pdev->dev, "Atmel micro ASIC version %s\n", micro->version); -+ -+ return 0; -+} -+ -+static int micro_remove(struct platform_device *pdev) -+{ -+ mfd_remove_devices(&pdev->dev); -+ Ser1UTCR3 &= ~(UTCR3_RXE | UTCR3_RIE); /* disable receive interrupt */ -+ Ser1UTCR3 &= ~(UTCR3_TXE | UTCR3_TIE); /* disable transmit interrupt */ -+ return 0; -+} -+ -+static const struct dev_pm_ops micro_dev_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(micro_suspend, micro_resume) -+}; -+ -+static struct platform_driver micro_device_driver = { -+ .driver = { -+ .name = "ipaq-h3xxx-micro", -+ .pm = µ_dev_pm_ops, -+ }, -+ .probe = micro_probe, -+ .remove = micro_remove, -+ /* .shutdown = micro_suspend, // FIXME */ -+}; -+module_platform_driver(micro_device_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("driver for iPAQ Atmel micro core and backlight"); -diff --git a/include/linux/mfd/ipaq-micro.h b/include/linux/mfd/ipaq-micro.h -new file mode 100644 -index 000000000000..74733ff8a5ff ---- /dev/null -+++ b/include/linux/mfd/ipaq-micro.h -@@ -0,0 +1,73 @@ -+/* -+ * Header file for the compaq Micro MFD -+ */ -+ -+#ifndef _MICRO_H_ -+#define _MICRO_H_ -+ -+#include <linux/spinlock.h> -+#include <linux/completion.h> -+struct device; -+ -+#define TX_BUF_SIZE 32 -+#define RX_BUF_SIZE 16 -+#define CHAR_SOF 0x02 -+ -+/* -+ * These are the different messages that can be sent to the microcontroller -+ * to control various aspects. -+ */ -+#define MSG_VERSION 0x00 -+#define MSG_KEYBOARD 0x02 -+#define MSG_TOUCHSCREEN 0x03 -+#define MSG_EEPROM_READ 0x04 -+#define MSG_EEPROM_WRITE 0x05 -+#define MSG_THERMAL_SENSOR 0x06 -+#define MSG_NOTIFY_LED 0x08 -+#define MSG_BATTERY 0x09 -+#define MSG_SPI_READ 0x0b -+#define MSG_SPI_WRITE 0x0c -+#define MSG_BACKLIGHT 0x0d /* H3600 only */ -+#define MSG_CODEC_CTRL 0x0e /* H3100 only */ -+#define MSG_DISPLAY_CTRL 0x0f /* H3100 only */ -+ -+/* state of receiver parser */ -+enum rx_state { -+ STATE_SOF = 0, /* Next byte should be start of frame */ -+ STATE_ID, /* Next byte is ID & message length */ -+ STATE_DATA, /* Next byte is a data byte */ -+ STATE_CHKSUM /* Next byte should be checksum */ -+}; -+ -+struct ipaq_micro_txdev { -+ unsigned char buf[TX_BUF_SIZE]; -+ atomic_t head; -+ atomic_t tail; -+}; -+ -+struct ipaq_micro_rxdev { -+ enum rx_state state; /* context of rx state machine */ -+ unsigned char chksum; /* calculated checksum */ -+ int id; /* message ID from packet */ -+ unsigned int len; /* rx buffer length */ -+ unsigned int index; /* rx buffer index */ -+ unsigned char buf[RX_BUF_SIZE]; /* rx buffer size */ -+}; -+ -+struct ipaq_micro { -+ struct device *dev; -+ char version[5]; -+ struct ipaq_micro_txdev tx; /* transmit ISR state */ -+ struct ipaq_micro_rxdev rx; /* receive ISR state */ -+ spinlock_t lock; -+ struct completion msg_ack; -+ void (*h_key) (int len, unsigned char *data); -+ void (*h_batt) (int len, unsigned char *data); -+ void (*h_temp) (int len, unsigned char *data); -+ void (*h_ts) (int len, unsigned char *data); -+}; -+ -+int ipaq_micro_tx_msg(struct ipaq_micro *micro, unsigned char id, -+ unsigned char len, unsigned char *data); -+ -+#endif /* _MICRO_H_ */ --- -1.8.3.1 - |