aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-yocto-3.10/h3600/0001-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3xxx.patch
diff options
context:
space:
mode:
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.patch527
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(&micro->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(&micro->msg_ack);
-+ spin_unlock(&micro->lock);
-+}
-+
-+static void micro_process_char(struct ipaq_micro *micro, u8 ch)
-+{
-+ struct ipaq_micro_rxdev *rx = &micro->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 = &micro->tx;
-+ int free_space;
-+ int i;
-+ u8 checksum;
-+ int head, tail;
-+
-+ /* After TX, an interrupt will be triggered that completes */
-+ init_completion(&micro->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(&micro->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 = &micro->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 = &micro->rx;
-+ struct ipaq_micro_txdev *tx = &micro->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 = &micro->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(&micro->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 = &micro_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
-