lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080708203213.GF18479@datenfreihafen.org>
Date:	Tue, 8 Jul 2008 22:32:13 +0200
From:	Stefan Schmidt <stefan@...enfreihafen.org>
To:	Daniel Ribeiro <drwyrm@...il.com>
Cc:	Eric Miao <eric.y.miao@...il.com>,
	pHilipp Zabel <philipp.zabel@...il.com>,
	linux-arm-kernel@...ts.arm.linux.org.uk, sameo@...nedhand.com,
	linux-kernel@...r.kernel.org
Subject: Re: [Patch 06/10] mfd: PCAP driver for the Motorola EZX GSM mobile
	phones

Hello.

On Tue, 2008-07-08 at 11:01, Daniel Ribeiro wrote:
> Eric Miao escreveu:
> > The irq2pcap[] array looks horrible to me. It's actually a sparse array.
> > Isn't there a nice 1:1 mapping using a formular??
> > 
> > Besides, the IRQ numbering scheme has now changed to a more generic way,
> > I suggest to pull from Russell's latest git tree and rebase the IRQ
> > part.
> 
> 	Will do as you suggested and get rid of the arrays.
> 
> > The following block of code:
> > 
> > +	if (pcap_data->cs >= 0) {
> > +		if (machine_is_ezx_a780() || machine_is_ezx_e680())
> > +			gpio_direction_output(pcap_data->cs, 1);
> > +		else
> > +			gpio_direction_output(pcap_data->cs, 0);
> > +	}
> > 
> > has 3 occurrences in the driver (2 in ezx_ssp_pcap_putget, 1 in ezx_pcap_probe)
> > which is good reason to fold this into the platform data.
> > 
> > Well, if the above is done in platform data, I guess you won't mind another bit
> > flag (e.g. PCAP_REDIRECT_IRQ or something alike) added in platform data, either
> 
> 	Moved to platform data. What should PCAP_REDIRECT_IRQ flag do?

Daniel fixed all of Philipps comments besides the voltage framework. From Eric
comments we updated to the new IRQ part and moved to platform data.

Open items we are still working on:
o Voltage framework. Is this needed for the first merge or can we switch to it
  with a later patch?
o Get rid of the arrays
o Eric, what do you like the PCAP_REDIRECT_IRQ flag to do?

Besides the left items we updated and tested the patch below:


Subject: [@num@/@...al@] mfd: PCAP driver for the Motorola EZX GSM mobile phones
To: sameo@...nedhand.com
Cc: philipp.zabel@...il.com, linux-kernel@...r.kernel.org

The PCAP Asic as present on EZX phones is a multi function device with voltage
regulators, irq expander, touch screen controller and audio codec.
It is connected to the processor via SPI, this driver provides read/write
functions to its registers and a irq demultiplexer.

Signed-off-by: Daniel Ribeiro <drwyrm@...il.com>

PATCH FOLLOWS
KernelVersion: 2.6-arm-git pxa branch

Index: linux-2.6-arm/drivers/mfd/ezx-pcap.c
===================================================================
--- /dev/null
+++ linux-2.6-arm/drivers/mfd/ezx-pcap.c
@@ -0,0 +1,372 @@
+/* Driver for Motorola PCAP2 as present in EZX phones
+ *
+ * This is both a SPI device driver for PCAP itself, as well as
+ * an IRQ demultiplexer for handling PCAP generated events such as
+ * headphone jack sense by downstream drivers.
+ *
+ * Copyright (C) 2006 Harald Welte <laforge@...nezx.org>
+ * Copyright (C) 2007-2008 Daniel Ribeiro <drwyrm@...il.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/proc_fs.h>
+#include <linux/mfd/ezx-pcap.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/ssp.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/regs-ssp.h>
+#include <asm/arch/mfp-pxa27x.h>
+#include <asm/arch/irqs.h>
+#include <asm/mach/irq.h>
+
+static DEFINE_SPINLOCK(ezx_ssp_lock);
+static struct ssp_dev ezx_ssp_dev;
+static struct ssp_state ezx_ssp_state;
+static struct pcap_platform_data *pcap_data;
+static int pcap_irq;
+
+static u_int32_t ezx_ssp_pcap_putget(u_int32_t data)
+{
+	unsigned long flag;
+	u_int32_t ret = 0;
+
+	spin_lock_irqsave(&ezx_ssp_lock, flag);
+	if (pcap_data->cs >= 0) {
+		if (pcap_data->config & CS_INVERTED)
+			gpio_set_value(pcap_data->cs, 0);
+		else
+			gpio_set_value(pcap_data->cs, 1);
+	}
+
+	ssp_write_word(&ezx_ssp_dev, data);
+	ssp_read_word(&ezx_ssp_dev, &ret);
+
+	if (pcap_data->cs >= 0) {
+		if (pcap_data->config & CS_INVERTED)
+			gpio_set_value(pcap_data->cs, 1);
+		else
+			gpio_set_value(pcap_data->cs, 0);
+	}
+
+	spin_unlock_irqrestore(&ezx_ssp_lock, flag);
+
+	return ret;
+}
+
+void ezx_pcap_write(u_int8_t reg_num, u_int32_t value)
+{
+	value &= PCAP_REGISTER_VALUE_MASK;
+	value |= PCAP_REGISTER_WRITE_OP_BIT
+		| (reg_num<<PCAP_REGISTER_ADDRESS_SHIFT);
+
+	ezx_ssp_pcap_putget(value);
+}
+EXPORT_SYMBOL_GPL(ezx_pcap_write);
+
+void ezx_pcap_read(u_int8_t reg_num, u_int32_t *value)
+{
+	u_int32_t frame = PCAP_REGISTER_READ_OP_BIT
+		| (reg_num<<PCAP_REGISTER_ADDRESS_SHIFT);
+
+	*value = ezx_ssp_pcap_putget(frame);
+}
+EXPORT_SYMBOL_GPL(ezx_pcap_read);
+
+void ezx_pcap_set_sw(u_int8_t sw, u_int8_t what, u_int8_t val)
+{
+	u_int32_t tmp;
+
+	ezx_pcap_read(PCAP_REG_LOWPWR, &tmp);
+	tmp &= ~(0xf << (sw + what));
+	tmp |= ((val & 0xf) << (sw + what));
+	ezx_pcap_write(PCAP_REG_LOWPWR, tmp);
+}
+EXPORT_SYMBOL_GPL(ezx_pcap_set_sw);
+
+static u_int8_t vaux_table[][8] = {
+	/*		EN	INDEX	MASK	STBY	LOWPWR	*/
+	[VAUX1]	= {	1,	2,	0x3,	22,	23,	},
+	[VAUX2]	= {	4,	5,	0x3,	0,	1,	},
+	[VAUX3]	= {	7,	8,	0xf,	2,	3,	},
+	[VAUX4]	= {	12,	13,	0x3,	4,	5,	},
+	[VSIM]	= {	17,	18,	0x1,	0xff,	6,	},
+	[VSIM2]	= {	16,	0xff,	0x0,	0xff,	7,	},
+	[VVIB]	= {	19,	20,	0x3,	0xff,	0xff,	},
+	[VC]	= {	0xff,	0xff,	0x0,	24,	0xff,	},
+};
+
+int ezx_pcap_set_vaux(u_int8_t vaux, u_int8_t what, u_int8_t val)
+{
+	u_int8_t reg, shift, mask;
+	u_int32_t tmp;
+
+	switch (what) {
+	case VAUX_EN:
+		reg = PCAP_REG_AUXVREG;
+		shift = vaux_table[vaux][VAUX_EN];
+		mask = 0x1;
+		break;
+	case VAUX_VAL:
+		reg = PCAP_REG_AUXVREG;
+		shift = vaux_table[vaux][VAUX_VAL];
+		mask = vaux_table[vaux][VAUX_MASK];
+		break;
+	case VAUX_STBY:
+		if (vaux == VAUX1) /* exception */
+			reg = PCAP_REG_AUXVREG;
+		else
+			reg = PCAP_REG_LOWPWR;
+		shift = vaux_table[vaux][VAUX_STBY];
+		mask = 0x1;
+		break;
+	case VAUX_LOWPWR:
+		if (vaux == VAUX1)
+			reg = PCAP_REG_AUXVREG;
+		else
+			reg = PCAP_REG_LOWPWR;
+		shift = vaux_table[vaux][VAUX_LOWPWR];
+		mask = 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* invalid setting */
+	if (shift == 0xff || val > mask)
+		return -EINVAL;
+
+	ezx_pcap_read(reg, &tmp);
+	tmp &= ~(mask << shift);
+	tmp |= ((val & mask) << shift);
+	ezx_pcap_write(reg, tmp);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ezx_pcap_set_vaux);
+
+/* IRQ Handling */
+
+/* Array indexed by BIT POSITION of PCAP register, returns IRQ number */
+static unsigned int pcap2irq[] = {
+	[0]     = EZX_IRQ_ADCDONE,
+	[1]     = EZX_IRQ_TS,
+	[2]     = EZX_IRQ_1HZ, /* 1HZ */
+	[3]     = EZX_IRQ_WH, /* WH */
+	[4]     = EZX_IRQ_WL, /* WL */
+	[5]     = EZX_IRQ_TODA, /* TODA */
+	[6]     = EZX_IRQ_USB4V,
+	[7]     = EZX_IRQ_ONOFF, /* ONOFF */
+	[8]     = EZX_IRQ_ONOFF2, /* ONOFF2 */
+	[9]     = EZX_IRQ_USB1V,
+	[10]    = EZX_IRQ_MOBPORT, /* MOBPORT */
+	[11]    = EZX_IRQ_MIC,
+	[12]    = EZX_IRQ_HEADJACK,
+	[13]    = EZX_IRQ_ST, /* ST */
+	[14]    = EZX_IRQ_PC, /* PC */
+	[15]    = EZX_IRQ_WARM, /* WARM */
+	[16]    = EZX_IRQ_EOL, /* EOL */
+	[17]    = EZX_IRQ_CLK, /* CLK */
+	[18]    = EZX_IRQ_SYSRST, /* SYSRST */
+	[19]    = 0,
+	[20]    = EZX_IRQ_ADCDONE2,
+	[21]    = EZX_IRQ_SOFTRESET, /* SOFTRESET */
+	[22]    = EZX_IRQ_MNEXB, /* MNEXB */
+};
+
+/* Array indexed by IRQ NUMBER, returns PCAP absolute value */
+static unsigned int irq2pcap[] = {
+	[EZX_IRQ_MNEXB]		= PCAP_IRQ_MNEXB,
+	[EZX_IRQ_SOFTRESET]	= PCAP_IRQ_SOFTRESET,
+	[EZX_IRQ_SYSRST]	= PCAP_IRQ_SYSRST,
+	[EZX_IRQ_CLK]		= PCAP_IRQ_CLK,
+	[EZX_IRQ_EOL]		= PCAP_IRQ_EOL,
+	[EZX_IRQ_WARM]		= PCAP_IRQ_WARM,
+	[EZX_IRQ_PC]		= PCAP_IRQ_PC,
+	[EZX_IRQ_ST]		= PCAP_IRQ_ST,
+	[EZX_IRQ_MOBPORT]	= PCAP_IRQ_MOBPORT,
+	[EZX_IRQ_ONOFF2]	= PCAP_IRQ_ONOFF2,
+	[EZX_IRQ_ONOFF]		= PCAP_IRQ_ONOFF,
+	[EZX_IRQ_TODA]		= PCAP_IRQ_TODA,
+	[EZX_IRQ_WL]		= PCAP_IRQ_WL,
+	[EZX_IRQ_WH]		= PCAP_IRQ_WH,
+	[EZX_IRQ_1HZ]		= PCAP_IRQ_1HZ,
+	[EZX_IRQ_USB4V]		= PCAP_IRQ_USB4V,
+	[EZX_IRQ_USB1V]		= PCAP_IRQ_USB1V,
+	[EZX_IRQ_HEADJACK]	= PCAP_IRQ_A1,
+	[EZX_IRQ_MIC]		= PCAP_IRQ_MB2,
+	[EZX_IRQ_TS]		= PCAP_IRQ_TS,
+	[EZX_IRQ_ADCDONE]	= PCAP_IRQ_ADCDONE,
+	[EZX_IRQ_ADCDONE2]	= PCAP_IRQ_ADCDONE2,
+};
+
+static void pcap_ack_irq(unsigned int irq)
+{
+	ezx_pcap_write(PCAP_REG_ISR, irq2pcap[irq]);
+}
+
+static void pcap_mask_irq(unsigned int irq)
+{
+	u_int32_t reg;
+	unsigned long flag;
+
+	spin_lock_irqsave(&ezx_ssp_lock, flag);
+	ezx_pcap_read(PCAP_REG_MSR, &reg);
+	reg |= irq2pcap[irq];
+	ezx_pcap_write(PCAP_REG_MSR, reg);
+	spin_unlock_irqrestore(&ezx_ssp_lock, flag);
+}
+
+static void pcap_unmask_irq(unsigned int irq)
+{
+	u_int32_t tmp;
+	unsigned long flag;
+
+	spin_lock_irqsave(&ezx_ssp_lock, flag);
+	ezx_pcap_read(PCAP_REG_MSR, &tmp);
+	tmp &= ~irq2pcap[irq];
+	ezx_pcap_write(PCAP_REG_MSR, tmp);
+	spin_unlock_irqrestore(&ezx_ssp_lock, flag);
+}
+
+static struct irq_chip pcap_chip = {
+	.name	= "ezx-pcap",
+	.ack    = pcap_ack_irq,
+	.mask   = pcap_mask_irq,
+	.unmask = pcap_unmask_irq,
+};
+
+/* handler for interrupt received from PCAP via GPIO */
+static void pcap_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int i;
+	u_int32_t isr;
+
+	desc->chip->ack(irq);
+	ezx_pcap_read(PCAP_REG_ISR, &isr);
+	for (i = ARRAY_SIZE(pcap2irq)-1; i >= 0; i--) {
+		unsigned int pirq = pcap2irq[i];
+		if (!(isr & irq2pcap[pirq]))
+			continue;
+		desc = &irq_desc[pirq];
+		desc_handle_irq(pirq, desc);
+	}
+}
+
+static int ezx_pcap_remove(struct platform_device *pdev)
+{
+	int irq;
+
+	set_irq_chained_handler(pcap_irq, NULL);
+	for (irq = EZX_IRQ(0); irq <= EZX_IRQ(21); irq++) {
+		set_irq_chip(irq, NULL);
+		set_irq_handler(irq, NULL);
+		set_irq_flags(irq, 0);
+	}
+	ssp_exit(&ezx_ssp_dev);
+
+	return 0;
+}
+
+static int __init ezx_pcap_probe(struct platform_device *pdev)
+{
+	unsigned int ret, irq;
+
+	pcap_data = pdev->dev.platform_data;
+	if (pcap_data->cs >= 0) {
+		if (pcap_data->config & CS_INVERTED)
+			gpio_direction_output(pcap_data->cs, 1);
+		else
+			gpio_direction_output(pcap_data->cs, 0);
+	}
+	pcap_irq = platform_get_irq(pdev, 0);
+	if (pcap_irq < 0) {
+		printk(KERN_ERR "Unable to get IRQ for pcap!\n");
+		return pcap_irq;
+	}
+
+	ret = ssp_init(&ezx_ssp_dev, pcap_data->port, 0);
+	if (ret) {
+		printk(KERN_ERR "Unable to register SSP handler!\n");
+		return ret;
+	}
+
+	ssp_disable(&ezx_ssp_dev);
+	ssp_config(&ezx_ssp_dev,
+		(SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS),
+		(SSCR1_TxTresh(1) | SSCR1_RxTresh(1)),
+		0, SSCR0_SerClkDiv(pcap_data->clk));
+	ssp_enable(&ezx_ssp_dev);
+
+	if (pcap_data->init)
+		pcap_data->init();
+
+	/* set up interrupt demultiplexing code for PCAP2 irqs */
+	for (irq = EZX_IRQ(0); irq <= EZX_IRQ(21); irq++) {
+		set_irq_chip(irq, &pcap_chip);
+		set_irq_handler(irq, handle_level_irq);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+	set_irq_type(pcap_irq, IRQ_TYPE_EDGE_RISING);
+	set_irq_chained_handler(pcap_irq, pcap_irq_demux_handler);
+	set_irq_wake(pcap_irq, 1);
+
+	/* mask/ack all PCAP interrupts */
+	ezx_pcap_write(PCAP_REG_MSR, PCAP_MASK_ALL_INTERRUPT);
+	ezx_pcap_write(PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER);
+
+
+	printk(KERN_INFO "ezx-pcap: ssp driver registered\n");
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int ezx_pcap_suspend(struct platform_device *dev, pm_message_t state)
+{
+	ssp_flush(&ezx_ssp_dev);
+	ssp_save_state(&ezx_ssp_dev, &ezx_ssp_state);
+	ssp_disable(&ezx_ssp_dev);
+	return 0;
+}
+
+static int ezx_pcap_resume(struct platform_device *dev)
+{
+	ssp_restore_state(&ezx_ssp_dev, &ezx_ssp_state);
+	ssp_enable(&ezx_ssp_dev);
+
+	return 0;
+}
+#endif
+
+static struct platform_driver ezxpcap_driver = {
+	.probe		= ezx_pcap_probe,
+	.remove		= ezx_pcap_remove,
+#ifdef CONFIG_PM
+	.suspend	= ezx_pcap_suspend,
+	.resume		= ezx_pcap_resume,
+#endif
+	.driver		= {
+		.name   = "ezx-pcap",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ezx_pcap_init(void)
+{
+	return platform_driver_register(&ezxpcap_driver);
+}
+
+subsys_initcall(ezx_pcap_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte");
+MODULE_DESCRIPTION("Motorola PCAP2 ASIC Driver");
Index: linux-2.6-arm/include/linux/mfd/ezx-pcap.h
===================================================================
--- /dev/null
+++ linux-2.6-arm/include/linux/mfd/ezx-pcap.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2007 Daniel Ribeiro <drwyrm@...il.com>
+ *
+ * For further information, please see http://wiki.openezx.org/PCAP2
+ */
+
+#ifndef EZX_PCAP_H
+#define EZX_PCAP_H
+
+struct pcap_platform_data {
+	int port;		/* SSP port */
+	int cs;			/* CS gpio */
+	int config;
+	int clk;
+	int (*init)(void);	/* board specific driver init */
+};
+
+#define CS_INVERTED	1
+
+#define PCAP_REGISTER_WRITE_OP_BIT	0x80000000
+#define PCAP_REGISTER_READ_OP_BIT	0x00000000
+
+#define PCAP_REGISTER_VALUE_MASK	0x01ffffff
+#define PCAP_REGISTER_ADDRESS_MASK	0x7c000000
+#define PCAP_REGISTER_ADDRESS_SHIFT	26
+#define PCAP_REGISTER_NUMBER		32
+#define PCAP_CLEAR_INTERRUPT_REGISTER	0x01ffffff
+#define PCAP_MASK_ALL_INTERRUPT		0x01ffffff
+
+#define pbit(reg, bit)	((reg << PCAP_REGISTER_ADDRESS_SHIFT) | bit)
+
+/* registers acessible by both pcap ports */
+#define PCAP_REG_ISR		0x0	/* Interrupt Status */
+#define PCAP_REG_MSR		0x1	/* Interrupt Mask */
+#define PCAP_REG_PSTAT		0x2	/* Processor Status */
+#define PCAP_REG_VREG2		0x6	/* Regulator Bank 2 Control */
+#define PCAP_REG_AUXVREG	0x7	/* Auxiliary Regulator Control */
+#define PCAP_REG_BATT		0x8	/* Battery Control */
+#define PCAP_REG_ADC		0x9	/* AD Control */
+#define PCAP_REG_ADR		0xa	/* AD Result */
+#define PCAP_REG_CODEC		0xb	/* Audio Codec Control */
+#define PCAP_REG_RX_AMPS	0xc	/* RX Audio Amplifiers Control */
+#define PCAP_REG_ST_DAC		0xd	/* Stereo DAC Control */
+#define PCAP_REG_BUSCTRL	0x14	/* Connectivity Control */
+#define PCAP_REG_PERIPH		0x15	/* Peripheral Control */
+#define PCAP_REG_LOWPWR		0x18	/* Regulator Low Power Control */
+#define PCAP_REG_TX_AMPS	0x1a	/* TX Audio Amplifiers Control */
+#define PCAP_REG_GP		0x1b	/* General Purpose */
+
+/* registers acessible by pcap port 1 only (a1200, e2 & e6) */
+#define PCAP_REG_INT_SEL	0x3	/* Interrupt Select */
+#define PCAP_REG_SWCTRL		0x4	/* Switching Regulator Control */
+#define PCAP_REG_VREG1		0x5	/* Regulator Bank 1 Control */
+#define PCAP_REG_RTC_TOD	0xe	/* RTC Time of Day */
+#define PCAP_REG_RTC_TODA	0xf	/* RTC Time of Day Alarm */
+#define PCAP_REG_RTC_DAY	0x10	/* RTC Day */
+#define PCAP_REG_RTC_DAYA	0x11	/* RTC Day Alarm */
+#define PCAP_REG_MTRTMR		0x12	/* AD Monitor Timer */
+#define PCAP_REG_PWR		0x13	/* Power Control */
+#define PCAP_REG_AUXVREG_MASK	0x16	/* Auxiliary Regulator Mask */
+#define PCAP_REG_VENDOR_REV	0x17
+#define PCAP_REG_PERIPH_MASK	0x19	/* Peripheral Mask */
+
+/* interrupts - registers 0x0, 0x1, 0x2, 0x3 */
+#define PCAP_IRQ_ADCDONE	(1 << 0)	/* AD Conversion Done Port 1 */
+#define PCAP_IRQ_TS		(1 << 1)	/* Touch Screen */
+#define PCAP_IRQ_1HZ		(1 << 2)	/* 1HZ Timer */
+#define PCAP_IRQ_WH		(1 << 3)	/* "...high"??? */
+#define PCAP_IRQ_WL		(1 << 4)	/* "...low"??? */
+#define PCAP_IRQ_TODA		(1 << 5)	/* RTC Time Of Day?
+						     (see "RTC_TODA") */
+#define PCAP_IRQ_USB4V		(1 << 6)	/* USB OTG */
+#define PCAP_IRQ_ONOFF		(1 << 7)	/* in blob: "ONOFFSNS" */
+#define PCAP_IRQ_ONOFF2		(1 << 8)	/* in blob: "ONOFFSNS2" */
+#define PCAP_IRQ_USB1V		(1 << 9)	/* USB below 1volt???
+						     in blob: "USBDET_1V" */
+#define PCAP_IRQ_MOBPORT	(1 << 10)	/* GSM-related?? ("mobport",
+				see 958_MotDoc.pdf); in blob: "MOBSENSB" */
+#define PCAP_IRQ_MB2		(1 << 11)	/* Mic; in blob: "MB2SNS" */
+#define PCAP_IRQ_A1		(1 << 12)	/* Audio jack;
+						     in blob: "A1SNS" */
+#define PCAP_IRQ_ST		(1 << 13)	/* called "MSTB" in blob */
+#define PCAP_IRQ_PC		(1 << 14)
+#define PCAP_IRQ_WARM		(1 << 15)
+#define PCAP_IRQ_EOL		(1 << 16)	/* battery End Of Life???
+					(see below); in blob: "EOL_STAT" */
+#define PCAP_IRQ_CLK		(1 << 17)	/* called "CLK_STAT" in blob */
+#define PCAP_IRQ_SYSRST		(1 << 18)
+#define PCAP_IRQ_ADCDONE2	(1 << 20)	/* AD Conversion Done Port 2 */
+#define PCAP_IRQ_SOFTRESET	(1 << 21)
+#define PCAP_IRQ_MNEXB		(1 << 22)
+
+/* register VREG2 (0x6) */
+#define PCAP_VREG2_V1_STBY	(1 << 0)
+#define PCAP_VREG2_V2_STBY	(1 << 1)
+/* V3, SRAM: */
+#define PCAP_VREG2_V3_STBY	(1 << 2)
+#define PCAP_VREG2_V4_STBY	(1 << 3)
+#define PCAP_VREG2_V5_STBY	(1 << 4)
+/* V6, E680 I2C camera?: */
+#define PCAP_VREG2_V6_STBY	(1 << 5)
+#define PCAP_VREG2_V7_STBY	(1 << 6)
+/* V8, PLL: */
+#define PCAP_VREG2_V8_STBY	(1 << 7)
+#define PCAP_VREG2_V9_STBY	(1 << 8)
+#define PCAP_VREG2_V10_STBY	(1 << 9)
+#define PCAP_VREG2_V1_LOWPWR	(1 << 10)
+#define PCAP_VREG2_V2_LOWPWR	(1 << 11)
+/* V3, SRAM: */
+#define PCAP_VREG2_V3_LOWPWR	(1 << 12)
+#define PCAP_VREG2_V4_LOWPWR	(1 << 13)
+#define PCAP_VREG2_V5_LOWPWR	(1 << 14)
+/* V6, E680 I2C camera?: */
+#define PCAP_VREG2_V6_LOWPWR	(1 << 15)
+#define PCAP_VREG2_V7_LOWPWR	(1 << 16)
+/* V8, PLL: */
+#define PCAP_VREG2_V8_LOWPWR	(1 << 17)
+#define PCAP_VREG2_V9_LOWPWR	(1 << 18)
+#define PCAP_VREG2_V10_LOWPWR	(1 << 19)
+
+/* register AUXVREG (0x7) */
+#define VAUX1		0
+#define VAUX2		1
+#define VAUX3		2
+#define VAUX4		3
+#define VSIM		4
+#define VSIM2		5
+#define VVIB		6
+#define VC		7
+
+#define VAUX_EN		0
+#define VAUX_VAL	1
+#define VAUX_MASK	2
+#define VAUX_STBY	3
+#define VAUX_LOWPWR	4
+
+#define PCAP_BATT_DAC_MASK		0x000000ff
+#define PCAP_BATT_DAC_SHIFT		0
+#define PCAP_BATT_B_FDBK		(1 << 8)
+#define PCAP_BATT_EXT_ISENSE		(1 << 9)
+#define PCAP_BATT_V_COIN_MASK		0x00003c00
+#define PCAP_BATT_V_COIN_SHIFT		10
+#define PCAP_BATT_I_COIN		(1 << 14)
+#define PCAP_BATT_COIN_CH_EN		(1 << 15)
+#define PCAP_BATT_EOL_SEL_MASK		0x000e0000
+#define PCAP_BATT_EOL_SEL_SHIFT		17
+#define PCAP_BATT_EOL_CMP_EN		(1 << 20)
+#define PCAP_BATT_BATT_DET_EN		(1 << 21)
+#define PCAP_BATT_THERMBIAS_CTRL	(1 << 22)
+
+#define PCAP_ADC_ADEN			(1 << 0)
+#define PCAP_ADC_RAND			(1 << 1)
+#define PCAP_ADC_AD_SEL1		(1 << 2)
+#define PCAP_ADC_AD_SEL2		(1 << 3)
+#define PCAP_ADC_ADA1_MASK		0x00000070
+#define PCAP_ADC_ADA1_SHIFT		4
+#define PCAP_ADC_ADA2_MASK		0x00000380
+#define PCAP_ADC_ADA2_SHIFT		7
+#define PCAP_ADC_ATO_MASK		0x00003c00
+#define PCAP_ADC_ATO_SHIFT		10
+#define PCAP_ADC_ATOX			(1 << 14)
+#define PCAP_ADC_MTR1			(1 << 15)
+#define PCAP_ADC_MTR2			(1 << 16)
+#define PCAP_ADC_TS_M_MASK		0x000e0000
+#define PCAP_ADC_TS_M_SHIFT		17
+#define PCAP_ADC_TS_REF_LOWPWR		(1 << 20)
+#define PCAP_ADC_TS_REFENB		(1 << 21)
+#define PCAP_ADC_BATT_I_POLARITY	(1 << 22)
+#define PCAP_ADC_BATT_I_ADC		(1 << 23)
+
+#define PCAP_ADR_ADD1_MASK		0x000003ff
+#define PCAP_ADR_ADD1_SHIFT		0
+#define PCAP_ADR_ADD2_MASK		0x000ffc00
+#define PCAP_ADR_ADD2_SHIFT		10
+#define PCAP_ADR_ADINC1			(1 << 20)
+#define PCAP_ADR_ADINC2			(1 << 21)
+#define PCAP_ADR_ASC			(1 << 22)
+#define PCAP_ADR_ONESHOT		(1 << 23)
+
+#define PCAP_BUSCTRL_FSENB		(1 << 0)
+#define PCAP_BUSCTRL_USB_SUSPEND	(1 << 1)
+#define PCAP_BUSCTRL_USB_PU		(1 << 2)
+#define PCAP_BUSCTRL_USB_PD		(1 << 3)
+#define PCAP_BUSCTRL_VUSB_EN		(1 << 4)
+#define PCAP_BUSCTRL_USB_PS		(1 << 5)
+#define PCAP_BUSCTRL_VUSB_MSTR_EN	(1 << 6)
+#define PCAP_BUSCTRL_VBUS_PD_ENB	(1 << 7)
+#define PCAP_BUSCTRL_CURRLIM		(1 << 8)
+#define PCAP_BUSCTRL_RS232ENB		(1 << 9)
+#define PCAP_BUSCTRL_RS232_DIR		(1 << 10)
+#define PCAP_BUSCTRL_SE0_CONN		(1 << 11)
+#define PCAP_BUSCTRL_USB_PDM		(1 << 12)
+#define PCAP_BUSCTRL_BUS_PRI_ADJ	(1 << 24)
+
+#define PCAP_BIT_PERIPH_BL_CTRL0	0x54000001
+#define PCAP_BIT_PERIPH_BL_CTRL1	0x54000002
+#define PCAP_BIT_PERIPH_BL_CTRL2	0x54000004
+#define PCAP_BIT_PERIPH_BL_CTRL3	0x54000008
+#define PCAP_BIT_PERIPH_BL_CTRL4	0x54000010
+#define PCAP_BIT_PERIPH_LEDR_EN		0x54000020
+#define PCAP_BIT_PERIPH_LEDG_EN		0x54000040
+#define PCAP_BIT_PERIPH_LEDR_CTRL0	0x54000080
+#define PCAP_BIT_PERIPH_LEDR_CTRL1	0x54000100
+#define PCAP_BIT_PERIPH_LEDR_CTRL2	0x54000200
+#define PCAP_BIT_PERIPH_LEDR_CTRL3	0x54000400
+#define PCAP_BIT_PERIPH_LEDG_CTRL0	0x54000800
+#define PCAP_BIT_PERIPH_LEDG_CTRL1	0x54001000
+#define PCAP_BIT_PERIPH_LEDG_CTRL2	0x54002000
+#define PCAP_BIT_PERIPH_LEDG_CTRL3	0x54004000
+#define PCAP_BIT_PERIPH_LEDR_I0		0x54008000
+#define PCAP_BIT_PERIPH_LEDR_I1		0x54010000
+#define PCAP_BIT_PERIPH_LEDG_I0		0x54020000
+#define PCAP_BIT_PERIPH_LEDG_I1		0x54040000
+#define PCAP_BIT_PERIPH_SKIP		0x54080000
+#define PCAP_BIT_PERIPH_BL2_CTRL0	0x54100000
+#define PCAP_BIT_PERIPH_BL2_CTRL1	0x54200000
+#define PCAP_BIT_PERIPH_BL2_CTRL2	0x54400000
+#define PCAP_BIT_PERIPH_BL2_CTRL3	0x54800000
+#define PCAP_BIT_PERIPH_BL2_CTRL4	0x55000000
+
+/* LOWPWR */
+#define SW1		8
+#define SW2		16
+
+#define SW_MODE		0
+#define SW_VOLTAGE	4
+
+#define SW_VOLTAGE_900	0x0
+#define SW_VOLTAGE_950	0x1
+#define SW_VOLTAGE_1000	0x2
+#define SW_VOLTAGE_1050	0x3
+#define SW_VOLTAGE_1100	0x4
+#define SW_VOLTAGE_1150	0x5
+#define SW_VOLTAGE_1200	0x6
+#define SW_VOLTAGE_1250	0x7
+#define SW_VOLTAGE_1300	0x8
+#define SW_VOLTAGE_1350	0x9
+#define SW_VOLTAGE_1400	0xa
+#define SW_VOLTAGE_1500	0xb
+#define SW_VOLTAGE_1600	0xc
+#define SW_VOLTAGE_1875	0xd
+#define SW_VOLTAGE_2250	0xe
+#define SW_VOLTAGE_4400	0xf
+
+void ezx_pcap_write(u_int8_t, u_int32_t);
+void ezx_pcap_read(u_int8_t, u_int32_t *);
+void ezx_pcap_set_sw(u_int8_t, u_int8_t, u_int8_t);
+int ezx_pcap_set_vaux(u_int8_t, u_int8_t, u_int8_t);
+#endif
Index: linux-2.6-arm/drivers/mfd/Kconfig
===================================================================
--- linux-2.6-arm.orig/drivers/mfd/Kconfig
+++ linux-2.6-arm/drivers/mfd/Kconfig
@@ -49,6 +49,13 @@
 	help
 	  Support for Toshiba Mobile IO Controller TC6393XB
 
+config EZX_PCAP
+	bool "PCAP Support"
+	depends on PXA_SSP && PXA_EZX
+	help
+	  This enables the PCAP ASIC present on EZX Phones. This is
+	  needed for MMC, TouchScreen, Sound, USB, etc..
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
Index: linux-2.6-arm/drivers/mfd/Makefile
===================================================================
--- linux-2.6-arm.orig/drivers/mfd/Makefile
+++ linux-2.6-arm/drivers/mfd/Makefile
@@ -12,6 +12,8 @@
 
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
+obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
Index: linux-2.6-arm/arch/arm/mach-pxa/Kconfig
===================================================================
--- linux-2.6-arm.orig/arch/arm/mach-pxa/Kconfig
+++ linux-2.6-arm/arch/arm/mach-pxa/Kconfig
@@ -251,6 +251,8 @@
 	select PXA27x
 	select IWMMXT
 	select HAVE_PWM
+	select PXA_SSP
+	select EZX_PCAP
 
 config MACH_EZX_A780
 	bool "Motorola EZX A780"
Index: linux-2.6-arm/arch/arm/mach-pxa/ezx.c
===================================================================
--- linux-2.6-arm.orig/arch/arm/mach-pxa/ezx.c
+++ linux-2.6-arm/arch/arm/mach-pxa/ezx.c
@@ -15,7 +15,9 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/pwm_backlight.h>
+#include <linux/mfd/ezx-pcap.h>
 
 #include <asm/setup.h>
 #include <asm/arch/pxafb.h>
@@ -87,7 +89,54 @@
 	.lcd_conn	= LCD_COLOR_TFT_18BPP,
 };
 
+/* PCAP */
+static int ezx_pcap_init(void)
+{
+	/* disable all voltage regulators */
+	ezx_pcap_write(PCAP_REG_AUXVREG, 0);
+
+	/* set SW1 sleep to keep SW1 1.3v in sync mode */
+	/*  SW1 active in sync mode */
+	ezx_pcap_set_sw(SW1, SW_MODE, 0x1);
+
+	/*  set core voltage */
+	ezx_pcap_set_sw(SW1, SW_VOLTAGE, SW_VOLTAGE_1250);
+
+	/* redirect all interrupts to AP */
+	if (!(machine_is_ezx_a780() || machine_is_ezx_e680()))
+		ezx_pcap_write(PCAP_REG_INT_SEL, 0);
+
+	return 0;
+}
+
+static struct pcap_platform_data ezx_pcap_platform_data = {
+	.port   = 1,
+	.cs     = 24,
+	.clk    = 1,
+	.config	= 0,
+	.init   = ezx_pcap_init,
+};
+
+static struct resource ezx_pcap_resources[] = {
+	[0] = {
+		.start      = IRQ_GPIO1,
+		.end        = IRQ_GPIO1,
+		.flags      = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device ezx_pcap_device = {
+	.name       = "ezx-pcap",
+	.id     = -1,
+	.num_resources  = ARRAY_SIZE(ezx_pcap_resources),
+	.resource   = ezx_pcap_resources,
+	.dev        = {
+		.platform_data = &ezx_pcap_platform_data,
+	},
+};
+
 static struct platform_device *devices[] __initdata = {
+	&ezx_pcap_device,
 	&ezx_backlight_device,
 };
 
@@ -105,6 +154,11 @@
 	GPIO46_STUART_RXD,
 	GPIO47_STUART_TXD,
 
+	/* PCAP SSP */
+	GPIO29_SSP1_SCLK,
+	GPIO25_SSP1_TXD,
+	GPIO26_SSP1_RXD,
+
 	/* For A780 support (connected with Neptune GSM chip) */
 	GPIO30_USB_P3_2,	/* ICL_TXENB */
 	GPIO31_USB_P3_6,	/* ICL_VPOUT */
@@ -118,11 +172,12 @@
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
 	pxa_set_i2c_info(NULL);
-	if (machine_is_ezx_a780() || machine_is_ezx_e680())
+	if (machine_is_ezx_a780() || machine_is_ezx_e680()) {
 		set_pxa_fb_info(&ezx_fb_info_1);
-	else
+		ezx_pcap_platform_data.config |= CS_INVERTED;
+	} else {
 		set_pxa_fb_info(&ezx_fb_info_2);
-
+	}
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
Index: linux-2.6-arm/include/asm-arm/arch-pxa/irqs.h
===================================================================
--- linux-2.6-arm.orig/include/asm-arm/arch-pxa/irqs.h
+++ linux-2.6-arm/include/asm-arm/arch-pxa/irqs.h
@@ -186,6 +186,39 @@
 #endif
 #endif /* CONFIG_MACH_PCM027 */
 
+#define EZX_IRQ(x)		PXA_BOARD_IRQ(x)
+
+#ifdef CONFIG_PXA_EZX
+#define EZX_IRQ_USB4V		EZX_IRQ(0) /* EMU */
+#define EZX_IRQ_USB1V		EZX_IRQ(1) /* EMU */
+#define EZX_IRQ_HEADJACK	EZX_IRQ(2) /* Audio connector */
+#define EZX_IRQ_MIC		EZX_IRQ(3) /* Audio connector */
+#define EZX_IRQ_ADCDONE		EZX_IRQ(4)
+#define EZX_IRQ_TS		EZX_IRQ(5) /* TS touch */
+#define EZX_IRQ_ADCDONE2	EZX_IRQ(6) /* TS x/y ADC ready */
+#define EZX_IRQ_WH		EZX_IRQ(7)
+#define EZX_IRQ_WL		EZX_IRQ(8)
+#define EZX_IRQ_ONOFF		EZX_IRQ(9)
+#define EZX_IRQ_ONOFF2		EZX_IRQ(10)
+#define EZX_IRQ_MOBPORT		EZX_IRQ(11)
+#define EZX_IRQ_TODA		EZX_IRQ(12)
+#define EZX_IRQ_1HZ		EZX_IRQ(13)
+#define EZX_IRQ_MNEXB		EZX_IRQ(14)
+#define EZX_IRQ_ST		EZX_IRQ(15)
+#define EZX_IRQ_PC		EZX_IRQ(16)
+#define EZX_IRQ_SYSRST		EZX_IRQ(17)
+#define EZX_IRQ_SOFTRESET	EZX_IRQ(18)
+#define EZX_IRQ_EOL		EZX_IRQ(19)
+#define EZX_IRQ_CLK		EZX_IRQ(20)
+#define EZX_IRQ_WARM		EZX_IRQ(21)
+#define EZX_LAST_IRQ		EZX_IRQ_WARM
+
+#if PXA_BOARD_IRQ_END < EZX_LAST_IRQ
+#undef  PXA_BOARD_IRQ_END
+#define PXA_BOARD_IRQ_END	EZX_LAST_IRQ
+#endif
+#endif /* CONFIG_EZX */
+
 /*
  * Extended IRQs for companion chips start from the last board-specific IRQ.
  * NOTE: unlike board specific IRQs, the number space for these IRQs cannot
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ