Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757329AbYGGTUV (ORCPT ); Mon, 7 Jul 2008 15:20:21 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755324AbYGGTUG (ORCPT ); Mon, 7 Jul 2008 15:20:06 -0400 Received: from sirius.lasnet.de ([78.47.116.19]:47725 "EHLO sirius.lasnet.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755243AbYGGTUB (ORCPT ); Mon, 7 Jul 2008 15:20:01 -0400 X-Greylist: delayed 2545 seconds by postgrey-1.27 at vger.kernel.org; Mon, 07 Jul 2008 15:19:59 EDT Message-Id: <20080707184129.554483476@datenfreihafen.org> References: <20080707184000.411913919@datenfreihafen.org> User-Agent: quilt/0.46-1 Date: Mon, 07 Jul 2008 20:40:06 +0200 From: stefan@datenfreihafen.org To: linux-arm-kernel@lists.arm.linux.org.uk, sameo@openedhand.com Cc: philipp.zabel@gmail.com, linux-kernel@vger.kernel.org, Daniel Ribeiro Content-Disposition: inline; filename=ezx-pcap.patch Subject: [Patch 06/10] mfd: PCAP driver for the Motorola EZX GSM mobile phones Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 25842 Lines: 863 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 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,402 @@ +/* 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 + * Copyright (C) 2007-2008 Daniel Ribeiro + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP(x, args...) printk(x, ## args) +#else +#define DEBUGP(x, args...) +#endif + +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 (machine_is_ezx_a780() || machine_is_ezx_e680()) + 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 (machine_is_ezx_a780() || machine_is_ezx_e680()) + 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< 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) +{ + DEBUGP("pcap_ack_irq: %u\n", 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); + DEBUGP("pcap_mask_irq: %u\n", irq); + ezx_pcap_read(PCAP_REG_MSR, ®); + 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); + DEBUGP("pcap_unmask_irq: %u\n", irq); + 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]; + DEBUGP("found irq %u\n", pirq); + desc_handle_irq(pirq, desc); + } +} + +static int ezx_pcap_remove(struct platform_device *pdev) +{ + int irq; + DEBUGP("exz_pcap_remove entered\n"); + + 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; + DEBUGP("ezx_pcap_probe entered\n"); + + pcap_data = pdev->dev.platform_data; + + 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); + } + 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) +{ + DEBUGP("pcap suspend!\n"); + 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) +{ + DEBUGP("pcap resume!\n"); + 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) +{ + DEBUGP("ezx_pcap_init entered\n"); + return platform_driver_register(&ezxpcap_driver); +} + +static void __exit ezx_pcap_exit(void) +{ + return platform_driver_unregister(&ezxpcap_driver); +} + +module_init(ezx_pcap_init); +module_exit(ezx_pcap_exit); + +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,248 @@ +/* + * Copyright 2007 Daniel Ribeiro + * + * 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 clk; + int (*init)(void); /* board specific driver init */ +}; + +#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 above 4volt??? + called "USBDET_4V" in blob */ +#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/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 @@ -89,7 +89,7 @@ * within sensible limits. */ #define IRQ_BOARD_START (PXA_GPIO_IRQ_BASE + PXA_GPIO_IRQ_NUM) -#define IRQ_BOARD_END (IRQ_BOARD_START + 16) +#define IRQ_BOARD_END (IRQ_BOARD_START + 22) #define IRQ_SA1111_START (IRQ_BOARD_END) #define IRQ_GPAIN0 (IRQ_BOARD_END + 0) @@ -183,7 +183,8 @@ defined(CONFIG_MACH_TOSA) || \ defined(CONFIG_MACH_MAINSTONE) || \ defined(CONFIG_MACH_PCM027) || \ - defined(CONFIG_MACH_MAGICIAN) + defined(CONFIG_MACH_MAGICIAN) || \ + defined(CONFIG_PXA_EZX) #define NR_IRQS (IRQ_BOARD_END) #else #define NR_IRQS (IRQ_BOARD_START) @@ -237,6 +238,31 @@ #define PCM027_MMCDET_IRQ PCM027_IRQ(2) #define PCM027_PM_5V_IRQ PCM027_IRQ(3) +/* EZX Interrupts (CONFIG_EZX) */ +#define EZX_IRQ(x) (IRQ_BOARD_START + (x)) +#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) + /* ITE8152 irqs */ /* add IT8152 IRQs beyond BOARD_END */ #ifdef CONFIG_PCI_HOST_ITE8152 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 @@ -224,6 +224,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 #include #include +#include #include +#include #include #include @@ -87,6 +89,51 @@ .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, + .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_backlight_device, }; @@ -105,6 +152,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 */ @@ -122,7 +174,7 @@ set_pxa_fb_info(&ezx_fb_info_1); else set_pxa_fb_info(&ezx_fb_info_2); - + platform_device_register(&ezx_pcap_device); platform_add_devices(devices, ARRAY_SIZE(devices)); } -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/