diff options
Diffstat (limited to 'recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0022-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3600.patch')
-rw-r--r-- | recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0022-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3600.patch | 553 |
1 files changed, 0 insertions, 553 deletions
diff --git a/recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0022-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3600.patch b/recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0022-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3600.patch deleted file mode 100644 index 46a3e8e..0000000 --- a/recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0022-MFD-driver-for-Atmel-Microcontroller-on-iPaq-h3600.patch +++ /dev/null @@ -1,553 +0,0 @@ -From c6132951729a8d37704f8c6b701be3358f538c0f 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 22/28] MFD: driver for Atmel Microcontroller on iPaq h3600/h3100 - -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. - -Signed-off-by: Dmitry Artamonow <mad_soft@inbox.ru> ---- - drivers/mfd/Kconfig | 5 + - drivers/mfd/Makefile | 4 +- - drivers/mfd/micro.c | 454 +++++++++++++++++++++++++++++++++++++++++++++ - include/linux/mfd/micro.h | 29 +++ - 4 files changed, 491 insertions(+), 1 deletions(-) - create mode 100644 drivers/mfd/micro.c - create mode 100644 include/linux/mfd/micro.h - -diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 06a2b0f..dbac30e 100644 ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -34,6 +34,11 @@ config MFD_ASIC3 - This driver supports the ASIC3 multifunction chip found on many - PDAs (mainly iPAQ and HTC based ones) - -+config IPAQ_MICRO -+ tristate "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" -+ depends on SA1100_H3600 || SA1100_H3100 -+ select MFD_CORE -+ - config MFD_DM355EVM_MSP - bool "DaVinci DM355 EVM microcontroller" - depends on I2C && MACH_DAVINCI_DM355_EVM -diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index 3afb519..3fb4b39 100644 ---- a/drivers/mfd/Makefile -+++ b/drivers/mfd/Makefile -@@ -5,6 +5,8 @@ - obj-$(CONFIG_MFD_SM501) += sm501.o - obj-$(CONFIG_MFD_ASIC3) += asic3.o - -+obj-$(CONFIG_IPAQ_MICRO) += micro.o -+ - obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o - obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o - -@@ -40,4 +42,4 @@ obj-$(CONFIG_PMIC_DA903X) += da903x.o - - obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o - obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o --obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o -\ No newline at end of file -+obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o -diff --git a/drivers/mfd/micro.c b/drivers/mfd/micro.c -new file mode 100644 -index 0000000..7a15df2 ---- /dev/null -+++ b/drivers/mfd/micro.c -@@ -0,0 +1,454 @@ -+/* -+ * 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. -+ * -+ * h3600 atmel micro companion support -+ * based on previous kernel 2.4 version -+ * Author : Alessandro Gardich <gremlin@gremlin.it> -+ * -+ */ -+ -+ -+#include <linux/module.h> -+#include <linux/version.h> -+ -+#include <linux/init.h> -+#include <linux/fs.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+#include <linux/pm.h> -+#include <linux/sysctl.h> -+#include <linux/proc_fs.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <linux/input.h> -+#include <linux/platform_device.h> -+#include <linux/backlight.h> -+#include <linux/fb.h> -+#include <linux/mfd/core.h> -+ -+#include <asm/irq.h> -+#include <asm/atomic.h> -+#include <mach/hardware.h> -+ -+#include <mach/h3600.h> -+#include <mach/SA-1100.h> -+ -+/* FIXME #include "../../arch/arm/mach-sa1100/generic.h" */ -+ -+#include <linux/mfd/micro.h> -+ -+#define TX_BUF_SIZE 32 -+#define RX_BUF_SIZE 16 -+#define CHAR_SOF 0x02 -+ -+/* 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 h3600_txdev { -+ unsigned char buf[TX_BUF_SIZE]; -+ atomic_t head; -+ atomic_t tail; -+}; -+static struct h3600_txdev tx; /* transmit ISR state */ -+ -+struct h3600_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 */ -+}; -+ -+static struct h3600_rxdev rx; /* receive ISR state */ -+ -+/*--- backlight ---*/ -+#define MAX_BRIGHTNESS 255 -+ -+static void micro_set_bl_intensity(int intensity) -+{ -+ unsigned char data[3]; -+ -+ data[0] = 0x01; -+ data[1] = intensity > 0 ? 1 : 0; -+ data[2] = intensity; -+ h3600_micro_tx_msg(0x0D, 3, data); -+} -+ -+static struct generic_bl_info micro_bl_info = { -+ .default_intensity = MAX_BRIGHTNESS / 4, -+ .limit_mask = 0xffff, -+ .max_intensity = MAX_BRIGHTNESS, -+ .set_bl_intensity = micro_set_bl_intensity, -+}; -+ -+/*--- manage messages from Atmel Micro ---*/ -+ -+static struct micro_private_t micro; -+ -+static void h3600_micro_rx_msg(int id, int len, unsigned char *data) -+{ -+ int i; -+ -+ /*printk(KERN_ERR "h3600_micro : got a message from micro\n");*/ -+ spin_lock(micro.lock); -+ switch (id) { -+ case 0x0D: /* backlight */ -+ /* empty ack, just ignore */ -+ break; -+ case 0x02: /* keyboard */ -+ if (micro.h_key != NULL) -+ micro.h_key(len, data); -+ else -+ printk(KERN_ERR "h3600_micro : key message ignored, " -+ "no handle \n"); -+ break; -+ case 0x03: /* touchscreen */ -+ if (micro.h_ts != NULL) -+ micro.h_ts(len, data); -+ else -+ printk(KERN_ERR "h3600_micro : touchscreen message" -+ " ignored, no handle \n"); -+ break; -+ case 0x06: /* temperature */ -+ if (micro.h_temp != NULL) -+ micro.h_temp(len, data); -+ else -+ printk(KERN_ERR "h3600_micro : temperature message" -+ " ignored, no handle \n"); -+ break; -+ case 0x09: /* battery */ -+ if (micro.h_batt != NULL) -+ micro.h_batt(len, data); -+ else -+ printk(KERN_ERR "h3600_micro : battery message" -+ " ignored, no handle \n"); -+ break; -+ default: -+ printk(KERN_ERR "h3600_micro : unknown msg %d [%d] ", id, len); -+ for (i = 0; i < len; ++i) -+ printk("0x%02x ", data[i]); -+ printk("\n"); -+ } -+ spin_unlock(micro.lock); -+} -+ -+/*--- low lever serial interface ---*/ -+ -+static void h3600_micro_process_char(unsigned char ch) -+{ -+ switch (rx.state) { -+ case STATE_SOF: /* Looking for SOF */ -+ if (ch == CHAR_SOF) -+ rx.state = STATE_ID; /* Next byte is the id and len */ -+ /* else -+ g_statistics.missing_sof++; // FIXME */ -+ 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) -+ h3600_micro_rx_msg(rx.id, rx.len, rx.buf); -+ /* else -+ g_statistics.bad_checksum++; //FIXME */ -+ rx.state = STATE_SOF; -+ break; -+ } -+} -+ -+static void h3600_micro_rx_chars(void) -+{ -+ unsigned int status, ch; -+ -+ while ((status = Ser1UTSR1) & UTSR1_RNE) { -+ ch = Ser1UTDR; -+ /* statistics.rx++; // FIXME */ -+ if (status & UTSR1_PRE) /* Parity error */ -+ printk(KERN_ERR "h3600_micro_rx : parity error\n"); -+ /* statistics.parity++; // FIXME */ -+ else if (status & UTSR1_FRE) /* Framing error */ -+ printk(KERN_ERR "h3600_micro_rx : framing error\n"); -+ /* statistics.frame++; // FIXME */ -+ else if (status & UTSR1_ROR) /* Overrun error */ -+ printk(KERN_ERR "h3600_micro_rx : overrun error\n"); -+ /*statistics.overrun++;*/ -+ h3600_micro_process_char(ch); -+ } -+} -+ -+int h3600_micro_tx_msg(unsigned char id, unsigned char len, unsigned char *data) -+{ -+ int free_space; -+ int i; -+ unsigned char checksum; -+ int head, tail; -+ -+ 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) { -+ printk(KERN_ERR "%s : no avaiable space on tx buffer.", -+ __func__); -+ return -EIO; -+ } -+ -+ if (0) -+ printk(KERN_ERR "%s : avaiable space %d %d %d\n", -+ __func__, free_space, head, tail); -+ -+ tx.buf[head] = (unsigned char) 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(h3600_micro_tx_msg); -+ -+ -+static void h3600_micro_tx_chars(void) -+{ -+ 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 h3600_micro_reset_comm(void) -+{ -+ printk(KERN_ERR "%s: initializing serial port\n", __func__); -+ -+ /* 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 */ -+} -+ -+/*--- core interrupt ---*/ -+enum MessageHandleType { -+ HANDLE_NORMAL, -+ HANDLE_ACK, -+ HANDLE_ERROR -+}; -+ -+#define MICRO_MSG_WAITING 0 -+#define MICRO_MSG_SUCCESS 1 -+#define MICRO_MSG_ERROR -1 -+ -+static irqreturn_t h3600_micro_serial_isr(int irq, void *dev_id) -+{ -+ unsigned int status; /* UTSR0 */ -+ int head, tail; -+ /* unsigned int pass_counter = 0; // FIXME */ -+ -+ if (0) -+ printk(KERN_ERR "%s\n", __func__); /* FIXME */ -+ -+ /* statistics.isr++; // FIXME */ -+ status = Ser1UTSR0; -+ do { -+ if (status & (UTSR0_RID | UTSR0_RFS)) { -+ if (status & UTSR0_RID) -+ /* Clear the Receiver IDLE bit */ -+ Ser1UTSR0 = UTSR0_RID; -+ h3600_micro_rx_chars(); -+ } -+ -+ /* Clear break bits */ -+ if (status & (UTSR0_RBB | UTSR0_REB)) -+ Ser1UTSR0 = status & (UTSR0_RBB | UTSR0_REB); -+ -+ if (status & UTSR0_TFS) -+ h3600_micro_tx_chars(); -+ -+ status = Ser1UTSR0; -+ -+ head = atomic_read(&tx.head); -+ tail = atomic_read(&tx.tail); -+ } while (((head != tail) && (status & UTSR0_TFS)) || -+ status & (UTSR0_RFS | UTSR0_RID)); -+ /* && pass_counter++ < H3600_TS_PASS_LIMIT ); */ -+/* -+ if ( pass_counter >= H3600_TS_PASS_LIMIT ) // FIXME -+ statistics.pass_limit++; -+*/ -+ -+ return IRQ_HANDLED; -+} -+ -+/*--- sub devices declaration ---*/ -+enum { -+ MICRO_CELL_BACKLIGHT, -+ MICRO_CELL_BATTERY, -+ MICRO_CELL_KEYS, -+ MICRO_CELL_TS, -+}; -+ -+static struct mfd_cell micro_cells[] = { -+ [MICRO_CELL_BACKLIGHT] = { -+ .name = "generic-bl", -+ .platform_data = µ_bl_info, -+ .data_size = sizeof(micro_bl_info), -+ }, -+ [MICRO_CELL_BATTERY] = { -+ .name = "h3600-micro-battery", -+ .driver_data = µ, -+ }, -+ [MICRO_CELL_KEYS] = { -+ .name = "h3600-micro-keys", -+ .driver_data = µ, -+ }, -+ [MICRO_CELL_TS] = { -+ .name = "h3600-micro-ts", -+ .driver_data = µ, -+ }, -+}; -+ -+/*--- micro ---*/ -+static int micro_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ printk(KERN_ERR "micro : suspend \n"); -+ /* __micro_backlight_set_power(FB_BLANK_POWERDOWN); // FIXME */ -+ return 0; -+} -+ -+static int micro_resume(struct platform_device *dev) -+{ -+ printk(KERN_ERR "micro : resume\n"); -+ h3600_micro_reset_comm(); -+ mdelay(10); -+ -+ return 0; -+} -+ -+static int micro_probe(struct platform_device *dev) -+{ -+ int result = 0; -+ /* struct platform_device *plat; */ -+ -+ printk(KERN_ERR "micro probe : begin \n"); -+ -+ h3600_micro_reset_comm(); -+ -+ result = request_irq(IRQ_Ser1UART, h3600_micro_serial_isr, -+ IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, -+ "h3600_micro", h3600_micro_serial_isr); -+ if (result) { -+ printk(KERN_CRIT "%s: unable to grab serial port IRQ\n", -+ __func__); -+ return result; -+ } else -+ printk(KERN_ERR "h3600_micro : grab serial port IRQ\n"); -+ -+ result = mfd_add_devices(&dev->dev, dev->id, micro_cells, -+ ARRAY_SIZE(micro_cells), NULL, 0); -+ if (result != 0) { -+ printk(KERN_ERR "micro probe : platform_add_devices" -+ " fail [%d].\n", result); -+ } -+ -+ spin_lock_init(µ.lock); -+ -+ printk(KERN_ERR "micro probe : end [%d]\n", result); -+ -+ return result; -+} -+ -+static int micro_remove(struct platform_device *dev) -+{ -+ int i; -+ -+ mfd_remove_devices(&dev->dev); -+ -+ Ser1UTCR3 &= ~(UTCR3_RXE | UTCR3_RIE); /* disable receive interrupt */ -+ Ser1UTCR3 &= ~(UTCR3_TXE | UTCR3_TIE); /* disable transmit interrupt */ -+ free_irq(IRQ_Ser1UART, h3600_micro_serial_isr); -+ return 0; -+} -+ -+static struct platform_driver micro_device_driver = { -+ .driver = { -+ .name = "h3600-micro", -+ }, -+ .probe = micro_probe, -+ .remove = micro_remove, -+ .suspend = micro_suspend, -+ .resume = micro_resume, -+ /* .shutdown = micro_suspend, // FIXME */ -+}; -+ -+static int micro_init(void) -+{ -+ return platform_driver_register(µ_device_driver); -+} -+ -+static void micro_cleanup(void) -+{ -+ platform_driver_unregister(µ_device_driver); -+} -+ -+module_init(micro_init); -+module_exit(micro_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("gremlin.it"); -+MODULE_DESCRIPTION("driver for iPAQ Atmel micro core and backlight"); -+ -diff --git a/include/linux/mfd/micro.h b/include/linux/mfd/micro.h -new file mode 100644 -index 0000000..7d185ec ---- /dev/null -+++ b/include/linux/mfd/micro.h -@@ -0,0 +1,29 @@ -+/* -+ * some definition of intercomunication structures for micro -+ * and it's sub devices -+ */ -+ -+#ifndef _MICRO_H_ -+#define _MICRO_H_ -+ -+#include <linux/spinlock.h> -+ -+ -+#define TX_BUF_SIZE 32 -+#define RX_BUF_SIZE 16 -+#define CHAR_SOF 0x02 -+ -+extern struct platform_device h3600micro_device; -+ -+struct micro_private_t { -+ spinlock_t lock; -+ 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 h3600_micro_tx_msg(unsigned char id, unsigned char len, -+ unsigned char *data); -+ -+#endif /* _MICRO_H_ */ --- -1.6.1.3 - |