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: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 8 Jul 2008 23:19:18 +0200
From:	"pHilipp Zabel" <philipp.zabel@...il.com>
To:	"Stefan Schmidt" <stefan@...enfreihafen.org>
Cc:	"Daniel Ribeiro" <drwyrm@...il.com>,
	"Eric Miao" <eric.y.miao@...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

On Tue, Jul 8, 2008 at 10:32 PM, Stefan Schmidt
<stefan@...enfreihafen.org> wrote:
> 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

No way, it's not even in mainline yet.
I just wanted to point out that this might be interesting in the future.

> 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