mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (212 commits) [ARM] pxa: Phycore pcm-990-specific code for the PXA270 Quick Capture driver [ARM] pxa: V4L2 soc_camera driver for PXA270 [ARM] pxa: restrict availability of pxa2xx PCMCIA drivers [ARM] 5005/1: BAST: Fix kset_name initialiser [ARM] 4967/1: Adds functions to set clkout rate for Samsung S3C2410 [ARM] 4988/1: Add GPIO lib support to the EP93xx [ARM] Add initial sparsemem support [ARM] pxa: initialise PXA devices before platform init code [ARM] 5002/1: tosa: add two more leds [ARM] 5004/1: Tosa: make several unreferenced structures static. [ARM] 5003/1: Shut up sparse warnings [ARM] 4977/2: soc - pxa2xx-ac97 - Add missing clk_enable() [ARM] 4976/1: zylonite: Configure GPIO for WM9713 IRQ line [ARM] 4974/1: Drop unused leds-tosa. [ARM] 4973/1: Tosa: use leds-gpio driver. [ARM] 4972/1: Tosa: convert scoop GPIOs usage to generic gpio code [ARM] 4971/1: pxaficp_ir: provide startup and shutdown hooks [ARM] pxa: lubbock: move mis-placed SPI info [ARM] 4970/1: tosa: correct gpio used for wake up. [ARM] 4966/1: magician: add MFP pin configuration ...
This commit is contained in:
commit
85b375a613
376 changed files with 34585 additions and 12018 deletions
|
|
@ -76,6 +76,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
|
|
@ -370,6 +371,9 @@ enum {
|
|||
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
|
||||
#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
|
||||
|
||||
#define WINDOW_CTRL(i) (0x20030 + ((i) << 4))
|
||||
#define WINDOW_BASE(i) (0x20034 + ((i) << 4))
|
||||
|
||||
enum {
|
||||
/* DMA boundary 0xffff is required by the s/g splitting
|
||||
* we need on /length/ in mv_fill-sg().
|
||||
|
|
@ -2769,6 +2773,27 @@ static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mv_conf_mbus_windows(struct mv_host_priv *hpriv,
|
||||
struct mbus_dram_target_info *dram)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
writel(0, hpriv->base + WINDOW_CTRL(i));
|
||||
writel(0, hpriv->base + WINDOW_BASE(i));
|
||||
}
|
||||
|
||||
for (i = 0; i < dram->num_cs; i++) {
|
||||
struct mbus_dram_window *cs = dram->cs + i;
|
||||
|
||||
writel(((cs->size - 1) & 0xffff0000) |
|
||||
(cs->mbus_attr << 8) |
|
||||
(dram->mbus_dram_target_id << 4) | 1,
|
||||
hpriv->base + WINDOW_CTRL(i));
|
||||
writel(cs->base, hpriv->base + WINDOW_BASE(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mv_platform_probe - handle a positive probe of an soc Marvell
|
||||
* host
|
||||
|
|
@ -2823,6 +2848,12 @@ static int mv_platform_probe(struct platform_device *pdev)
|
|||
res->end - res->start + 1);
|
||||
hpriv->base -= MV_SATAHC0_REG_BASE;
|
||||
|
||||
/*
|
||||
* (Re-)program MBUS remapping windows if we are asked to.
|
||||
*/
|
||||
if (mv_platform_data->dram != NULL)
|
||||
mv_conf_mbus_windows(hpriv, mv_platform_data->dram);
|
||||
|
||||
rc = mv_create_dma_pools(hpriv, &pdev->dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -645,7 +645,7 @@ config I2C_PCA_ISA
|
|||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on (MV64X60 || ARCH_ORION) && EXPERIMENTAL
|
||||
depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <asm/io.h>
|
||||
#include <asm/arch/i2c.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/pxa2xx-gpio.h>
|
||||
|
||||
struct pxa_i2c {
|
||||
spinlock_t lock;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ config ISP1301_OMAP
|
|||
|
||||
config TPS65010
|
||||
tristate "TPS6501x Power Management chips"
|
||||
depends on HAVE_GPIO_LIB
|
||||
default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
|
||||
help
|
||||
If you say yes here you get support for the TPS6501x series of
|
||||
|
|
|
|||
|
|
@ -30,9 +30,13 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/i2c/tps65010.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define DRIVER_VERSION "2 May 2005"
|
||||
|
|
@ -84,7 +88,9 @@ struct tps65010 {
|
|||
u8 chgstatus, regstatus, chgconf;
|
||||
u8 nmask1, nmask2;
|
||||
|
||||
/* not currently tracking GPIO state */
|
||||
u8 outmask;
|
||||
struct gpio_chip chip;
|
||||
struct platform_device *leds;
|
||||
};
|
||||
|
||||
#define POWER_POLL_DELAY msecs_to_jiffies(5000)
|
||||
|
|
@ -447,6 +453,59 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* offsets 0..3 == GPIO1..GPIO4
|
||||
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
|
||||
*/
|
||||
static void
|
||||
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
if (offset < 4)
|
||||
tps65010_set_gpio_out_value(offset + 1, value);
|
||||
else
|
||||
tps65010_set_led(offset - 3, value ? ON : OFF);
|
||||
}
|
||||
|
||||
static int
|
||||
tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
/* GPIOs may be input-only */
|
||||
if (offset < 4) {
|
||||
struct tps65010 *tps;
|
||||
|
||||
tps = container_of(chip, struct tps65010, chip);
|
||||
if (!(tps->outmask & (1 << offset)))
|
||||
return -EINVAL;
|
||||
tps65010_set_gpio_out_value(offset + 1, value);
|
||||
} else
|
||||
tps65010_set_led(offset - 3, value ? ON : OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int value;
|
||||
struct tps65010 *tps;
|
||||
|
||||
tps = container_of(chip, struct tps65010, chip);
|
||||
|
||||
if (offset < 4) {
|
||||
value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
|
||||
if (value < 0)
|
||||
return 0;
|
||||
if (value & (1 << (offset + 4))) /* output */
|
||||
return !(value & (1 << offset));
|
||||
else /* input */
|
||||
return (value & (1 << offset));
|
||||
}
|
||||
|
||||
/* REVISIT we *could* report LED1/nPG and LED2 state ... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct tps65010 *the_tps;
|
||||
|
|
@ -454,7 +513,14 @@ static struct tps65010 *the_tps;
|
|||
static int __exit tps65010_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tps65010 *tps = i2c_get_clientdata(client);
|
||||
struct tps65010_board *board = client->dev.platform_data;
|
||||
|
||||
if (board && board->teardown) {
|
||||
int status = board->teardown(client, board->context);
|
||||
if (status < 0)
|
||||
dev_dbg(&client->dev, "board %s %s err %d\n",
|
||||
"teardown", client->name, status);
|
||||
}
|
||||
if (client->irq > 0)
|
||||
free_irq(client->irq, tps);
|
||||
cancel_delayed_work(&tps->work);
|
||||
|
|
@ -469,6 +535,7 @@ static int tps65010_probe(struct i2c_client *client)
|
|||
{
|
||||
struct tps65010 *tps;
|
||||
int status;
|
||||
struct tps65010_board *board = client->dev.platform_data;
|
||||
|
||||
if (the_tps) {
|
||||
dev_dbg(&client->dev, "only one tps6501x chip allowed\n");
|
||||
|
|
@ -577,6 +644,38 @@ static int tps65010_probe(struct i2c_client *client)
|
|||
|
||||
tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
|
||||
tps, DEBUG_FOPS);
|
||||
|
||||
/* optionally register GPIOs */
|
||||
if (board && board->base > 0) {
|
||||
tps->outmask = board->outmask;
|
||||
|
||||
tps->chip.label = client->name;
|
||||
|
||||
tps->chip.set = tps65010_gpio_set;
|
||||
tps->chip.direction_output = tps65010_output;
|
||||
|
||||
/* NOTE: only partial support for inputs; nyet IRQs */
|
||||
tps->chip.get = tps65010_gpio_get;
|
||||
|
||||
tps->chip.base = board->base;
|
||||
tps->chip.ngpio = 6;
|
||||
tps->chip.can_sleep = 1;
|
||||
|
||||
status = gpiochip_add(&tps->chip);
|
||||
if (status < 0)
|
||||
dev_err(&client->dev, "can't add gpiochip, err %d\n",
|
||||
status);
|
||||
else if (board->setup) {
|
||||
status = board->setup(client, board->context);
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev,
|
||||
"board %s %s err %d\n",
|
||||
"setup", client->name, status);
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail1:
|
||||
kfree(tps);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <asm/arch/corgi.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/pxa2xx-gpio.h>
|
||||
#include <asm/hardware/scoop.h>
|
||||
|
||||
#define KB_ROWS 8
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <asm/arch/spitz.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/pxa2xx-gpio.h>
|
||||
|
||||
#define KB_ROWS 7
|
||||
#define KB_COLS 11
|
||||
|
|
|
|||
|
|
@ -28,13 +28,6 @@
|
|||
#include <linux/spi/ads7846.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
#include <asm/mach-types.h>
|
||||
#ifdef CONFIG_ARCH_OMAP
|
||||
#include <asm/arch/gpio.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This code has been heavily tested on a Nokia 770, and lightly
|
||||
|
|
@ -1174,31 +1167,6 @@ static struct spi_driver ads7846_driver = {
|
|||
|
||||
static int __init ads7846_init(void)
|
||||
{
|
||||
/* grr, board-specific init should stay out of drivers!! */
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP
|
||||
if (machine_is_omap_osk()) {
|
||||
/* GPIO4 = PENIRQ; GPIO6 = BUSY */
|
||||
omap_request_gpio(4);
|
||||
omap_set_gpio_direction(4, 1);
|
||||
omap_request_gpio(6);
|
||||
omap_set_gpio_direction(6, 1);
|
||||
}
|
||||
// also TI 1510 Innovator, bitbanging through FPGA
|
||||
// also Nokia 770
|
||||
// also Palm Tungsten T2
|
||||
#endif
|
||||
|
||||
// PXA:
|
||||
// also Dell Axim X50
|
||||
// also HP iPaq H191x/H192x/H415x/H435x
|
||||
// also Intel Lubbock (additional to UCB1400; as temperature sensor)
|
||||
// also Sharp Zaurus C7xx, C8xx (corgi/sheperd/husky)
|
||||
|
||||
// Atmel at91sam9261-EK uses ads7843
|
||||
|
||||
// also various AMD Au1x00 devel boards
|
||||
|
||||
return spi_register_driver(&ads7846_driver);
|
||||
}
|
||||
module_init(ads7846_init);
|
||||
|
|
@ -1206,14 +1174,6 @@ module_init(ads7846_init);
|
|||
static void __exit ads7846_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ads7846_driver);
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP
|
||||
if (machine_is_omap_osk()) {
|
||||
omap_free_gpio(4);
|
||||
omap_free_gpio(6);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
module_exit(ads7846_exit);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <asm/arch/sharpsl.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/pxa2xx-gpio.h>
|
||||
|
||||
|
||||
#define PWR_MODE_ACTIVE 0
|
||||
|
|
|
|||
|
|
@ -46,13 +46,6 @@ config LEDS_SPITZ
|
|||
This option enables support for the LEDs on Sharp Zaurus
|
||||
SL-Cxx00 series (C1000, C3000, C3100).
|
||||
|
||||
config LEDS_TOSA
|
||||
tristate "LED Support for the Sharp SL-6000 series"
|
||||
depends on LEDS_CLASS && PXA_SHARPSL
|
||||
help
|
||||
This option enables support for the LEDs on Sharp Zaurus
|
||||
SL-6000 series.
|
||||
|
||||
config LEDS_S3C24XX
|
||||
tristate "LED Support for Samsung S3C24XX GPIO LEDs"
|
||||
depends on LEDS_CLASS && ARCH_S3C2410
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
|
|||
obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o
|
||||
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
|
||||
obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o
|
||||
obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o
|
||||
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
|
||||
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
|
||||
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
|
||||
|
|
|
|||
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
* LED Triggers Core
|
||||
*
|
||||
* Copyright 2005 Dirk Opfer
|
||||
*
|
||||
* Author: Dirk Opfer <Dirk@Opfer-Online.de>
|
||||
* based on spitz.c
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <asm/hardware/scoop.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/tosa.h>
|
||||
|
||||
static void tosaled_amber_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
if (value)
|
||||
set_scoop_gpio(&tosascoop_jc_device.dev,
|
||||
TOSA_SCOOP_JC_CHRG_ERR_LED);
|
||||
else
|
||||
reset_scoop_gpio(&tosascoop_jc_device.dev,
|
||||
TOSA_SCOOP_JC_CHRG_ERR_LED);
|
||||
}
|
||||
|
||||
static void tosaled_green_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
if (value)
|
||||
set_scoop_gpio(&tosascoop_jc_device.dev,
|
||||
TOSA_SCOOP_JC_NOTE_LED);
|
||||
else
|
||||
reset_scoop_gpio(&tosascoop_jc_device.dev,
|
||||
TOSA_SCOOP_JC_NOTE_LED);
|
||||
}
|
||||
|
||||
static struct led_classdev tosa_amber_led = {
|
||||
.name = "tosa:amber:charge",
|
||||
.default_trigger = "sharpsl-charge",
|
||||
.brightness_set = tosaled_amber_set,
|
||||
};
|
||||
|
||||
static struct led_classdev tosa_green_led = {
|
||||
.name = "tosa:green:mail",
|
||||
.default_trigger = "nand-disk",
|
||||
.brightness_set = tosaled_green_set,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tosaled_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name,
|
||||
"sharpsl-charge"))
|
||||
#endif
|
||||
led_classdev_suspend(&tosa_amber_led);
|
||||
led_classdev_suspend(&tosa_green_led);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tosaled_resume(struct platform_device *dev)
|
||||
{
|
||||
led_classdev_resume(&tosa_amber_led);
|
||||
led_classdev_resume(&tosa_green_led);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define tosaled_suspend NULL
|
||||
#define tosaled_resume NULL
|
||||
#endif
|
||||
|
||||
static int tosaled_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &tosa_amber_led);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &tosa_green_led);
|
||||
if (ret < 0)
|
||||
led_classdev_unregister(&tosa_amber_led);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tosaled_remove(struct platform_device *pdev)
|
||||
{
|
||||
led_classdev_unregister(&tosa_amber_led);
|
||||
led_classdev_unregister(&tosa_green_led);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tosaled_driver = {
|
||||
.probe = tosaled_probe,
|
||||
.remove = tosaled_remove,
|
||||
.suspend = tosaled_suspend,
|
||||
.resume = tosaled_resume,
|
||||
.driver = {
|
||||
.name = "tosa-led",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init tosaled_init(void)
|
||||
{
|
||||
return platform_driver_register(&tosaled_driver);
|
||||
}
|
||||
|
||||
static void __exit tosaled_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tosaled_driver);
|
||||
}
|
||||
|
||||
module_init(tosaled_init);
|
||||
module_exit(tosaled_exit);
|
||||
|
||||
MODULE_AUTHOR("Dirk Opfer <[email protected]>");
|
||||
MODULE_DESCRIPTION("Tosa LED driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:tosa-led");
|
||||
|
|
@ -22,6 +22,22 @@ config MFD_ASIC3
|
|||
This driver supports the ASIC3 multifunction chip found on many
|
||||
PDAs (mainly iPAQ and HTC based ones)
|
||||
|
||||
config HTC_EGPIO
|
||||
bool "HTC EGPIO support"
|
||||
depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB
|
||||
help
|
||||
This driver supports the CPLD egpio chip present on
|
||||
several HTC phones. It provides basic support for input
|
||||
pins, output pins, and irqs.
|
||||
|
||||
config HTC_PASIC3
|
||||
tristate "HTC PASIC3 LED/DS1WM chip support"
|
||||
help
|
||||
This core driver provides register access for the LED/DS1WM
|
||||
chips labeled "AIC2" and "AIC3", found on HTC Blueangel and
|
||||
HTC Magician devices, respectively. Actual functionality is
|
||||
handled by the leds-pasic3 and ds1wm drivers.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Multimedia Capabilities Port drivers"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
obj-$(CONFIG_MFD_SM501) += sm501.o
|
||||
obj-$(CONFIG_MFD_ASIC3) += asic3.o
|
||||
|
||||
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
|
||||
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
|
||||
|
||||
obj-$(CONFIG_MCP) += mcp-core.o
|
||||
obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
|
||||
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
|
||||
|
|
|
|||
440
drivers/mfd/htc-egpio.c
Normal file
440
drivers/mfd/htc-egpio.c
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
* Support for the GPIO/IRQ expander chips present on several HTC phones.
|
||||
* These are implemented in CPLD chips present on the board.
|
||||
*
|
||||
* Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net>
|
||||
* Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
|
||||
*
|
||||
* This file may be distributed under the terms of the GNU GPL license.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/htc-egpio.h>
|
||||
|
||||
struct egpio_chip {
|
||||
int reg_start;
|
||||
int cached_values;
|
||||
unsigned long is_out;
|
||||
struct device *dev;
|
||||
struct gpio_chip chip;
|
||||
};
|
||||
|
||||
struct egpio_info {
|
||||
spinlock_t lock;
|
||||
|
||||
/* iomem info */
|
||||
void __iomem *base_addr;
|
||||
int bus_shift; /* byte shift */
|
||||
int reg_shift; /* bit shift */
|
||||
int reg_mask;
|
||||
|
||||
/* irq info */
|
||||
int ack_register;
|
||||
int ack_write;
|
||||
u16 irqs_enabled;
|
||||
uint irq_start;
|
||||
int nirqs;
|
||||
uint chained_irq;
|
||||
|
||||
/* egpio info */
|
||||
struct egpio_chip *chip;
|
||||
int nchips;
|
||||
};
|
||||
|
||||
static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg)
|
||||
{
|
||||
writew(value, ei->base_addr + (reg << ei->bus_shift));
|
||||
}
|
||||
|
||||
static inline u16 egpio_readw(struct egpio_info *ei, int reg)
|
||||
{
|
||||
return readw(ei->base_addr + (reg << ei->bus_shift));
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQs
|
||||
*/
|
||||
|
||||
static inline void ack_irqs(struct egpio_info *ei)
|
||||
{
|
||||
egpio_writew(ei->ack_write, ei, ei->ack_register);
|
||||
pr_debug("EGPIO ack - write %x to base+%x\n",
|
||||
ei->ack_write, ei->ack_register << ei->bus_shift);
|
||||
}
|
||||
|
||||
static void egpio_ack(unsigned int irq)
|
||||
{
|
||||
}
|
||||
|
||||
/* There does not appear to be a way to proactively mask interrupts
|
||||
* on the egpio chip itself. So, we simply ignore interrupts that
|
||||
* aren't desired. */
|
||||
static void egpio_mask(unsigned int irq)
|
||||
{
|
||||
struct egpio_info *ei = get_irq_chip_data(irq);
|
||||
ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));
|
||||
pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled);
|
||||
}
|
||||
static void egpio_unmask(unsigned int irq)
|
||||
{
|
||||
struct egpio_info *ei = get_irq_chip_data(irq);
|
||||
ei->irqs_enabled |= 1 << (irq - ei->irq_start);
|
||||
pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled);
|
||||
}
|
||||
|
||||
static struct irq_chip egpio_muxed_chip = {
|
||||
.name = "htc-egpio",
|
||||
.ack = egpio_ack,
|
||||
.mask = egpio_mask,
|
||||
.unmask = egpio_unmask,
|
||||
};
|
||||
|
||||
static void egpio_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct egpio_info *ei = get_irq_data(irq);
|
||||
int irqpin;
|
||||
|
||||
/* Read current pins. */
|
||||
unsigned long readval = egpio_readw(ei, ei->ack_register);
|
||||
pr_debug("IRQ reg: %x\n", (unsigned int)readval);
|
||||
/* Ack/unmask interrupts. */
|
||||
ack_irqs(ei);
|
||||
/* Process all set pins. */
|
||||
readval &= ei->irqs_enabled;
|
||||
for_each_bit(irqpin, &readval, ei->nirqs) {
|
||||
/* Run irq handler */
|
||||
pr_debug("got IRQ %d\n", irqpin);
|
||||
irq = ei->irq_start + irqpin;
|
||||
desc = &irq_desc[irq];
|
||||
desc->handle_irq(irq, desc);
|
||||
}
|
||||
}
|
||||
|
||||
int htc_egpio_get_wakeup_irq(struct device *dev)
|
||||
{
|
||||
struct egpio_info *ei = dev_get_drvdata(dev);
|
||||
|
||||
/* Read current pins. */
|
||||
u16 readval = egpio_readw(ei, ei->ack_register);
|
||||
/* Ack/unmask interrupts. */
|
||||
ack_irqs(ei);
|
||||
/* Return first set pin. */
|
||||
readval &= ei->irqs_enabled;
|
||||
return ei->irq_start + ffs(readval) - 1;
|
||||
}
|
||||
EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
|
||||
|
||||
static inline int egpio_pos(struct egpio_info *ei, int bit)
|
||||
{
|
||||
return bit >> ei->reg_shift;
|
||||
}
|
||||
|
||||
static inline int egpio_bit(struct egpio_info *ei, int bit)
|
||||
{
|
||||
return 1 << (bit & ((1 << ei->reg_shift)-1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Input pins
|
||||
*/
|
||||
|
||||
static int egpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct egpio_chip *egpio;
|
||||
struct egpio_info *ei;
|
||||
unsigned bit;
|
||||
int reg;
|
||||
int value;
|
||||
|
||||
pr_debug("egpio_get_value(%d)\n", chip->base + offset);
|
||||
|
||||
egpio = container_of(chip, struct egpio_chip, chip);
|
||||
ei = dev_get_drvdata(egpio->dev);
|
||||
bit = egpio_bit(ei, offset);
|
||||
reg = egpio->reg_start + egpio_pos(ei, offset);
|
||||
|
||||
value = egpio_readw(ei, reg);
|
||||
pr_debug("readw(%p + %x) = %x\n",
|
||||
ei->base_addr, reg << ei->bus_shift, value);
|
||||
return value & bit;
|
||||
}
|
||||
|
||||
static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct egpio_chip *egpio;
|
||||
|
||||
egpio = container_of(chip, struct egpio_chip, chip);
|
||||
return test_bit(offset, &egpio->is_out) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Output pins
|
||||
*/
|
||||
|
||||
static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
unsigned long flag;
|
||||
struct egpio_chip *egpio;
|
||||
struct egpio_info *ei;
|
||||
unsigned bit;
|
||||
int pos;
|
||||
int reg;
|
||||
int shift;
|
||||
|
||||
pr_debug("egpio_set(%s, %d(%d), %d)\n",
|
||||
chip->label, offset, offset+chip->base, value);
|
||||
|
||||
egpio = container_of(chip, struct egpio_chip, chip);
|
||||
ei = dev_get_drvdata(egpio->dev);
|
||||
bit = egpio_bit(ei, offset);
|
||||
pos = egpio_pos(ei, offset);
|
||||
reg = egpio->reg_start + pos;
|
||||
shift = pos << ei->reg_shift;
|
||||
|
||||
pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear",
|
||||
reg, (egpio->cached_values >> shift) & ei->reg_mask);
|
||||
|
||||
spin_lock_irqsave(&ei->lock, flag);
|
||||
if (value)
|
||||
egpio->cached_values |= (1 << offset);
|
||||
else
|
||||
egpio->cached_values &= ~(1 << offset);
|
||||
egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg);
|
||||
spin_unlock_irqrestore(&ei->lock, flag);
|
||||
}
|
||||
|
||||
static int egpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct egpio_chip *egpio;
|
||||
|
||||
egpio = container_of(chip, struct egpio_chip, chip);
|
||||
if (test_bit(offset, &egpio->is_out)) {
|
||||
egpio_set(chip, offset, value);
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void egpio_write_cache(struct egpio_info *ei)
|
||||
{
|
||||
int i;
|
||||
struct egpio_chip *egpio;
|
||||
int shift;
|
||||
|
||||
for (i = 0; i < ei->nchips; i++) {
|
||||
egpio = &(ei->chip[i]);
|
||||
if (!egpio->is_out)
|
||||
continue;
|
||||
|
||||
for (shift = 0; shift < egpio->chip.ngpio;
|
||||
shift += (1<<ei->reg_shift)) {
|
||||
|
||||
int reg = egpio->reg_start + egpio_pos(ei, shift);
|
||||
|
||||
if (!((egpio->is_out >> shift) & ei->reg_mask))
|
||||
continue;
|
||||
|
||||
pr_debug("EGPIO: setting %x to %x, was %x\n", reg,
|
||||
(egpio->cached_values >> shift) & ei->reg_mask,
|
||||
egpio_readw(ei, reg));
|
||||
|
||||
egpio_writew((egpio->cached_values >> shift)
|
||||
& ei->reg_mask, ei, reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Setup
|
||||
*/
|
||||
|
||||
static int __init egpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct htc_egpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
struct egpio_info *ei;
|
||||
struct gpio_chip *chip;
|
||||
unsigned int irq, irq_end;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Initialize ei data structure. */
|
||||
ei = kzalloc(sizeof(*ei), GFP_KERNEL);
|
||||
if (!ei)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&ei->lock);
|
||||
|
||||
/* Find chained irq */
|
||||
ret = -EINVAL;
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (res)
|
||||
ei->chained_irq = res->start;
|
||||
|
||||
/* Map egpio chip into virtual address space. */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
goto fail;
|
||||
ei->base_addr = ioremap_nocache(res->start, res->end - res->start);
|
||||
if (!ei->base_addr)
|
||||
goto fail;
|
||||
pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr);
|
||||
|
||||
if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
|
||||
goto fail;
|
||||
ei->bus_shift = fls(pdata->bus_width - 1) - 3;
|
||||
pr_debug("bus_shift = %d\n", ei->bus_shift);
|
||||
|
||||
if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
|
||||
goto fail;
|
||||
ei->reg_shift = fls(pdata->reg_width - 1);
|
||||
pr_debug("reg_shift = %d\n", ei->reg_shift);
|
||||
|
||||
ei->reg_mask = (1 << pdata->reg_width) - 1;
|
||||
|
||||
platform_set_drvdata(pdev, ei);
|
||||
|
||||
ei->nchips = pdata->num_chips;
|
||||
ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL);
|
||||
if (!ei) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < ei->nchips; i++) {
|
||||
ei->chip[i].reg_start = pdata->chip[i].reg_start;
|
||||
ei->chip[i].cached_values = pdata->chip[i].initial_values;
|
||||
ei->chip[i].is_out = pdata->chip[i].direction;
|
||||
ei->chip[i].dev = &(pdev->dev);
|
||||
chip = &(ei->chip[i].chip);
|
||||
chip->label = "htc-egpio";
|
||||
chip->get = egpio_get;
|
||||
chip->set = egpio_set;
|
||||
chip->direction_input = egpio_direction_input;
|
||||
chip->direction_output = egpio_direction_output;
|
||||
chip->base = pdata->chip[i].gpio_base;
|
||||
chip->ngpio = pdata->chip[i].num_gpios;
|
||||
|
||||
gpiochip_add(chip);
|
||||
}
|
||||
|
||||
/* Set initial pin values */
|
||||
egpio_write_cache(ei);
|
||||
|
||||
ei->irq_start = pdata->irq_base;
|
||||
ei->nirqs = pdata->num_irqs;
|
||||
ei->ack_register = pdata->ack_register;
|
||||
|
||||
if (ei->chained_irq) {
|
||||
/* Setup irq handlers */
|
||||
ei->ack_write = 0xFFFF;
|
||||
if (pdata->invert_acks)
|
||||
ei->ack_write = 0;
|
||||
irq_end = ei->irq_start + ei->nirqs;
|
||||
for (irq = ei->irq_start; irq < irq_end; irq++) {
|
||||
set_irq_chip(irq, &egpio_muxed_chip);
|
||||
set_irq_chip_data(irq, ei);
|
||||
set_irq_handler(irq, handle_simple_irq);
|
||||
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
}
|
||||
set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING);
|
||||
set_irq_data(ei->chained_irq, ei);
|
||||
set_irq_chained_handler(ei->chained_irq, egpio_handler);
|
||||
ack_irqs(ei);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
printk(KERN_ERR "EGPIO failed to setup\n");
|
||||
kfree(ei);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit egpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct egpio_info *ei = platform_get_drvdata(pdev);
|
||||
unsigned int irq, irq_end;
|
||||
|
||||
if (ei->chained_irq) {
|
||||
irq_end = ei->irq_start + ei->nirqs;
|
||||
for (irq = ei->irq_start; irq < irq_end; irq++) {
|
||||
set_irq_chip(irq, NULL);
|
||||
set_irq_handler(irq, NULL);
|
||||
set_irq_flags(irq, 0);
|
||||
}
|
||||
set_irq_chained_handler(ei->chained_irq, NULL);
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
}
|
||||
iounmap(ei->base_addr);
|
||||
kfree(ei->chip);
|
||||
kfree(ei);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int egpio_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct egpio_info *ei = platform_get_drvdata(pdev);
|
||||
|
||||
if (ei->chained_irq && device_may_wakeup(&pdev->dev))
|
||||
enable_irq_wake(ei->chained_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int egpio_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct egpio_info *ei = platform_get_drvdata(pdev);
|
||||
|
||||
if (ei->chained_irq && device_may_wakeup(&pdev->dev))
|
||||
disable_irq_wake(ei->chained_irq);
|
||||
|
||||
/* Update registers from the cache, in case
|
||||
the CPLD was powered off during suspend */
|
||||
egpio_write_cache(ei);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define egpio_suspend NULL
|
||||
#define egpio_resume NULL
|
||||
#endif
|
||||
|
||||
|
||||
static struct platform_driver egpio_driver = {
|
||||
.driver = {
|
||||
.name = "htc-egpio",
|
||||
},
|
||||
.remove = __exit_p(egpio_remove),
|
||||
.suspend = egpio_suspend,
|
||||
.resume = egpio_resume,
|
||||
};
|
||||
|
||||
static int __init egpio_init(void)
|
||||
{
|
||||
return platform_driver_probe(&egpio_driver, egpio_probe);
|
||||
}
|
||||
|
||||
static void __exit egpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&egpio_driver);
|
||||
}
|
||||
|
||||
/* start early for dependencies */
|
||||
subsys_initcall(egpio_init);
|
||||
module_exit(egpio_exit)
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin O'Connor <[email protected]>");
|
||||
265
drivers/mfd/htc-pasic3.c
Normal file
265
drivers/mfd/htc-pasic3.c
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Core driver for HTC PASIC3 LED/DS1WM chip.
|
||||
*
|
||||
* Copyright (C) 2006 Philipp Zabel <philipp.zabel@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/ds1wm.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/htc-pasic3.h>
|
||||
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
|
||||
struct pasic3_data {
|
||||
void __iomem *mapping;
|
||||
unsigned int bus_shift;
|
||||
struct platform_device *ds1wm_pdev;
|
||||
struct platform_device *led_pdev;
|
||||
};
|
||||
|
||||
#define REG_ADDR 5
|
||||
#define REG_DATA 6
|
||||
#define NUM_REGS 7
|
||||
|
||||
#define READ_MODE 0x80
|
||||
|
||||
/*
|
||||
* write to a secondary register on the PASIC3
|
||||
*/
|
||||
void pasic3_write_register(struct device *dev, u32 reg, u8 val)
|
||||
{
|
||||
struct pasic3_data *asic = dev->driver_data;
|
||||
int bus_shift = asic->bus_shift;
|
||||
void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
|
||||
void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
|
||||
|
||||
__raw_writeb(~READ_MODE & reg, addr);
|
||||
__raw_writeb(val, data);
|
||||
}
|
||||
EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */
|
||||
|
||||
/*
|
||||
* read from a secondary register on the PASIC3
|
||||
*/
|
||||
u8 pasic3_read_register(struct device *dev, u32 reg)
|
||||
{
|
||||
struct pasic3_data *asic = dev->driver_data;
|
||||
int bus_shift = asic->bus_shift;
|
||||
void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
|
||||
void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
|
||||
|
||||
__raw_writeb(READ_MODE | reg, addr);
|
||||
return __raw_readb(data);
|
||||
}
|
||||
EXPORT_SYMBOL(pasic3_read_register); /* for leds-pasic3 */
|
||||
|
||||
/*
|
||||
* LEDs
|
||||
*/
|
||||
|
||||
static int led_device_add(struct device *pasic3_dev,
|
||||
const struct pasic3_leds_machinfo *pdata)
|
||||
{
|
||||
struct pasic3_data *asic = pasic3_dev->driver_data;
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc("pasic3-led", -1);
|
||||
if (!pdev) {
|
||||
dev_dbg(pasic3_dev, "failed to allocate LED platform device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(pdev, pdata,
|
||||
sizeof(struct pasic3_leds_machinfo));
|
||||
if (ret < 0) {
|
||||
dev_dbg(pasic3_dev, "failed to add LED platform data\n");
|
||||
goto exit_pdev_put;
|
||||
}
|
||||
|
||||
pdev->dev.parent = pasic3_dev;
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret < 0) {
|
||||
dev_dbg(pasic3_dev, "failed to add LED platform device\n");
|
||||
goto exit_pdev_put;
|
||||
}
|
||||
|
||||
asic->led_pdev = pdev;
|
||||
return 0;
|
||||
|
||||
exit_pdev_put:
|
||||
platform_device_put(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* DS1WM
|
||||
*/
|
||||
|
||||
static void ds1wm_enable(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = pdev->dev.parent;
|
||||
int c;
|
||||
|
||||
c = pasic3_read_register(dev, 0x28);
|
||||
pasic3_write_register(dev, 0x28, c & 0x7f);
|
||||
|
||||
dev_dbg(dev, "DS1WM OWM_EN low (active) %02x\n", c & 0x7f);
|
||||
}
|
||||
|
||||
static void ds1wm_disable(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = pdev->dev.parent;
|
||||
int c;
|
||||
|
||||
c = pasic3_read_register(dev, 0x28);
|
||||
pasic3_write_register(dev, 0x28, c | 0x80);
|
||||
|
||||
dev_dbg(dev, "DS1WM OWM_EN high (inactive) %02x\n", c | 0x80);
|
||||
}
|
||||
|
||||
static struct ds1wm_platform_data ds1wm_pdata = {
|
||||
.bus_shift = 2,
|
||||
.enable = ds1wm_enable,
|
||||
.disable = ds1wm_disable,
|
||||
};
|
||||
|
||||
static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift)
|
||||
{
|
||||
struct pasic3_data *asic = pasic3_dev->driver_data;
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc("ds1wm", -1);
|
||||
if (!pdev) {
|
||||
dev_dbg(pasic3_dev, "failed to allocate DS1WM platform device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = platform_device_add_resources(pdev, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret < 0) {
|
||||
dev_dbg(pasic3_dev, "failed to add DS1WM resources\n");
|
||||
goto exit_pdev_put;
|
||||
}
|
||||
|
||||
ds1wm_pdata.bus_shift = asic->bus_shift;
|
||||
ret = platform_device_add_data(pdev, &ds1wm_pdata,
|
||||
sizeof(struct ds1wm_platform_data));
|
||||
if (ret < 0) {
|
||||
dev_dbg(pasic3_dev, "failed to add DS1WM platform data\n");
|
||||
goto exit_pdev_put;
|
||||
}
|
||||
|
||||
pdev->dev.parent = pasic3_dev;
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret < 0) {
|
||||
dev_dbg(pasic3_dev, "failed to add DS1WM platform device\n");
|
||||
goto exit_pdev_put;
|
||||
}
|
||||
|
||||
asic->ds1wm_pdev = pdev;
|
||||
return 0;
|
||||
|
||||
exit_pdev_put:
|
||||
platform_device_put(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init pasic3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pasic3_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pasic3_data *asic;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r)
|
||||
return -ENXIO;
|
||||
|
||||
if (!request_mem_region(r->start, r->end - r->start + 1, "pasic3"))
|
||||
return -EBUSY;
|
||||
|
||||
asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL);
|
||||
if (!asic)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, asic);
|
||||
|
||||
if (pdata && pdata->bus_shift)
|
||||
asic->bus_shift = pdata->bus_shift;
|
||||
else
|
||||
asic->bus_shift = 2;
|
||||
|
||||
asic->mapping = ioremap(r->start, r->end - r->start + 1);
|
||||
if (!asic->mapping) {
|
||||
dev_err(dev, "couldn't ioremap PASIC3\n");
|
||||
kfree(asic);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = ds1wm_device_add(dev, asic->bus_shift);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "failed to register DS1WM\n");
|
||||
|
||||
if (pdata->led_pdata) {
|
||||
ret = led_device_add(dev, pdata->led_pdata);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "failed to register LED device\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pasic3_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pasic3_data *asic = platform_get_drvdata(pdev);
|
||||
struct resource *r;
|
||||
|
||||
if (asic->led_pdev)
|
||||
platform_device_unregister(asic->led_pdev);
|
||||
if (asic->ds1wm_pdev)
|
||||
platform_device_unregister(asic->ds1wm_pdev);
|
||||
|
||||
iounmap(asic->mapping);
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(r->start, r->end - r->start + 1);
|
||||
kfree(asic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pasic3_driver = {
|
||||
.driver = {
|
||||
.name = "pasic3",
|
||||
},
|
||||
.remove = pasic3_remove,
|
||||
};
|
||||
|
||||
static int __init pasic3_base_init(void)
|
||||
{
|
||||
return platform_driver_probe(&pasic3_driver, pasic3_probe);
|
||||
}
|
||||
|
||||
static void __exit pasic3_base_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pasic3_driver);
|
||||
}
|
||||
|
||||
module_init(pasic3_base_init);
|
||||
module_exit(pasic3_base_exit);
|
||||
|
||||
MODULE_AUTHOR("Philipp Zabel <[email protected]>");
|
||||
MODULE_DESCRIPTION("Core driver for HTC PASIC3");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -314,7 +314,7 @@ config MTD_ALAUDA
|
|||
|
||||
config MTD_NAND_ORION
|
||||
tristate "NAND Flash support for Marvell Orion SoC"
|
||||
depends on ARCH_ORION && MTD_NAND
|
||||
depends on PLAT_ORION && MTD_NAND
|
||||
help
|
||||
This enables the NAND flash controller on Orion machines.
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
#include <linux/mtd/partitions.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <asm/arch/platform.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/plat-orion/orion_nand.h>
|
||||
|
||||
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||
static const char *part_probes[] = { "cmdlinepart", NULL };
|
||||
|
|
|
|||
|
|
@ -2335,7 +2335,7 @@ config UGETH_TX_ON_DEMAND
|
|||
|
||||
config MV643XX_ETH
|
||||
tristate "Marvell Discovery (643XX) and Orion ethernet support"
|
||||
depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION
|
||||
depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
|
||||
select MII
|
||||
help
|
||||
This driver supports the gigabit ethernet MACs in the
|
||||
|
|
|
|||
|
|
@ -1043,7 +1043,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
|
|||
} else if (machine_is_csb337()) {
|
||||
/* mix link activity status into LED2 link state */
|
||||
write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
|
||||
}
|
||||
} else if (machine_is_ecbat91())
|
||||
write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
|
||||
|
||||
disable_mdi();
|
||||
spin_unlock_irq(&lp->lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <asm/hardware.h>
|
||||
#include <asm/arch/irda.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/pxa2xx-gpio.h>
|
||||
|
||||
#ifdef CONFIG_MACH_MAINSTONE
|
||||
#include <asm/arch/mainstone.h>
|
||||
|
|
@ -831,6 +832,11 @@ static int pxa_irda_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
goto err_mem_5;
|
||||
|
||||
if (si->pdata->startup)
|
||||
err = si->pdata->startup(si->dev);
|
||||
if (err)
|
||||
goto err_startup;
|
||||
|
||||
dev->hard_start_xmit = pxa_irda_hard_xmit;
|
||||
dev->open = pxa_irda_start;
|
||||
dev->stop = pxa_irda_stop;
|
||||
|
|
@ -856,6 +862,9 @@ static int pxa_irda_probe(struct platform_device *pdev)
|
|||
dev_set_drvdata(&pdev->dev, dev);
|
||||
|
||||
if (err) {
|
||||
if (si->pdata->shutdown)
|
||||
si->pdata->shutdown(si->dev);
|
||||
err_startup:
|
||||
kfree(si->tx_buff.head);
|
||||
err_mem_5:
|
||||
kfree(si->rx_buff.head);
|
||||
|
|
@ -881,6 +890,8 @@ static int pxa_irda_remove(struct platform_device *_dev)
|
|||
if (dev) {
|
||||
struct pxa_irda *si = netdev_priv(dev);
|
||||
unregister_netdev(dev);
|
||||
if (si->pdata->shutdown)
|
||||
si->pdata->shutdown(si->dev);
|
||||
kfree(si->tx_buff.head);
|
||||
kfree(si->rx_buff.head);
|
||||
clk_put(si->fir_clk);
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ config PCMCIA_AU1X00
|
|||
config PCMCIA_SA1100
|
||||
tristate "SA1100 support"
|
||||
depends on ARM && ARCH_SA1100 && PCMCIA
|
||||
depends on ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL || MACH_ARMCORE
|
||||
help
|
||||
Say Y here to include support for SA11x0-based PCMCIA or CF
|
||||
sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <asm/hardware.h>
|
||||
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/pxa2xx-gpio.h>
|
||||
#include <asm/arch/cm-x270.h>
|
||||
|
||||
#include "soc_common.h"
|
||||
|
|
|
|||
|
|
@ -166,15 +166,6 @@
|
|||
#define SERIAL_IMX_MAJOR 204
|
||||
#define MINOR_START 41
|
||||
|
||||
#define NR_PORTS 2
|
||||
|
||||
#define IMX_ISR_PASS_LIMIT 256
|
||||
|
||||
/*
|
||||
* This is the size of our serial port register set.
|
||||
*/
|
||||
#define UART_PORT_SIZE 0x100
|
||||
|
||||
/*
|
||||
* This determines how often we check the modem status signals
|
||||
* for any change. They generally aren't connected to an IRQ
|
||||
|
|
@ -358,66 +349,60 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
|
|||
struct tty_struct *tty = sport->port.info->tty;
|
||||
unsigned long flags, temp;
|
||||
|
||||
rx = readl(sport->port.membase + URXD0);
|
||||
spin_lock_irqsave(&sport->port.lock,flags);
|
||||
|
||||
do {
|
||||
while (readl(sport->port.membase + USR2) & USR2_RDR) {
|
||||
flg = TTY_NORMAL;
|
||||
sport->port.icount.rx++;
|
||||
|
||||
rx = readl(sport->port.membase + URXD0);
|
||||
|
||||
temp = readl(sport->port.membase + USR2);
|
||||
if( temp & USR2_BRCD ) {
|
||||
if (temp & USR2_BRCD) {
|
||||
writel(temp | USR2_BRCD, sport->port.membase + USR2);
|
||||
if(uart_handle_break(&sport->port))
|
||||
goto ignore_char;
|
||||
if (uart_handle_break(&sport->port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char
|
||||
(&sport->port, (unsigned char)rx))
|
||||
goto ignore_char;
|
||||
continue;
|
||||
|
||||
if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) )
|
||||
goto handle_error;
|
||||
if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
|
||||
if (rx & URXD_PRERR)
|
||||
sport->port.icount.parity++;
|
||||
else if (rx & URXD_FRMERR)
|
||||
sport->port.icount.frame++;
|
||||
if (rx & URXD_OVRRUN)
|
||||
sport->port.icount.overrun++;
|
||||
|
||||
if (rx & sport->port.ignore_status_mask) {
|
||||
if (++ignored > 100)
|
||||
goto out;
|
||||
continue;
|
||||
}
|
||||
|
||||
rx &= sport->port.read_status_mask;
|
||||
|
||||
if (rx & URXD_PRERR)
|
||||
flg = TTY_PARITY;
|
||||
else if (rx & URXD_FRMERR)
|
||||
flg = TTY_FRAME;
|
||||
if (rx & URXD_OVRRUN)
|
||||
flg = TTY_OVERRUN;
|
||||
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
sport->port.sysrq = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
error_return:
|
||||
tty_insert_flip_char(tty, rx, flg);
|
||||
|
||||
ignore_char:
|
||||
rx = readl(sport->port.membase + URXD0);
|
||||
} while(rx & URXD_CHARRDY);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&sport->port.lock,flags);
|
||||
tty_flip_buffer_push(tty);
|
||||
return IRQ_HANDLED;
|
||||
|
||||
handle_error:
|
||||
if (rx & URXD_PRERR)
|
||||
sport->port.icount.parity++;
|
||||
else if (rx & URXD_FRMERR)
|
||||
sport->port.icount.frame++;
|
||||
if (rx & URXD_OVRRUN)
|
||||
sport->port.icount.overrun++;
|
||||
|
||||
if (rx & sport->port.ignore_status_mask) {
|
||||
if (++ignored > 100)
|
||||
goto out;
|
||||
goto ignore_char;
|
||||
}
|
||||
|
||||
rx &= sport->port.read_status_mask;
|
||||
|
||||
if (rx & URXD_PRERR)
|
||||
flg = TTY_PARITY;
|
||||
else if (rx & URXD_FRMERR)
|
||||
flg = TTY_FRAME;
|
||||
if (rx & URXD_OVRRUN)
|
||||
flg = TTY_OVERRUN;
|
||||
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
sport->port.sysrq = 0;
|
||||
#endif
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -546,7 +531,7 @@ static int imx_startup(struct uart_port *port)
|
|||
writel(USR1_RTSD, sport->port.membase + USR1);
|
||||
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
temp |= (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
|
||||
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
|
||||
writel(temp, sport->port.membase + UCR1);
|
||||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
|
|
@ -731,9 +716,11 @@ static const char *imx_type(struct uart_port *port)
|
|||
*/
|
||||
static void imx_release_port(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
struct resource *mmres;
|
||||
|
||||
release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
|
||||
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(mmres->start, mmres->end - mmres->start + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -741,10 +728,18 @@ static void imx_release_port(struct uart_port *port)
|
|||
*/
|
||||
static int imx_request_port(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
struct resource *mmres;
|
||||
void *ret;
|
||||
|
||||
return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
|
||||
"imx-uart") != NULL ? 0 : -EBUSY;
|
||||
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mmres)
|
||||
return -ENODEV;
|
||||
|
||||
ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
|
||||
"imx-uart");
|
||||
|
||||
return ret ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -815,7 +810,7 @@ static struct imx_port imx_ports[] = {
|
|||
.type = PORT_IMX,
|
||||
.iotype = UPIO_MEM,
|
||||
.membase = (void *)IMX_UART1_BASE,
|
||||
.mapbase = IMX_UART1_BASE, /* FIXME */
|
||||
.mapbase = 0x00206000,
|
||||
.irq = UART1_MINT_RX,
|
||||
.uartclk = 16000000,
|
||||
.fifosize = 32,
|
||||
|
|
@ -831,7 +826,7 @@ static struct imx_port imx_ports[] = {
|
|||
.type = PORT_IMX,
|
||||
.iotype = UPIO_MEM,
|
||||
.membase = (void *)IMX_UART2_BASE,
|
||||
.mapbase = IMX_UART2_BASE, /* FIXME */
|
||||
.mapbase = 0x00207000,
|
||||
.irq = UART2_MINT_RX,
|
||||
.uartclk = 16000000,
|
||||
.fifosize = 32,
|
||||
|
|
|
|||
|
|
@ -1033,7 +1033,7 @@ MODULE_LICENSE ("GPL");
|
|||
#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_ORION
|
||||
#ifdef CONFIG_PLAT_ORION
|
||||
#include "ehci-orion.c"
|
||||
#define PLATFORM_DRIVER ehci_orion_driver
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -11,15 +11,18 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/arch/orion.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <asm/plat-orion/ehci-orion.h>
|
||||
|
||||
#define rdl(off) __raw_readl(hcd->regs + (off))
|
||||
#define wrl(off, val) __raw_writel((val), hcd->regs + (off))
|
||||
|
||||
#define USB_CAUSE 0x310
|
||||
#define USB_MASK 0x314
|
||||
#define USB_CMD 0x140
|
||||
#define USB_MODE 0x1a8
|
||||
#define USB_CAUSE 0x310
|
||||
#define USB_MASK 0x314
|
||||
#define USB_WINDOW_CTRL(i) (0x320 + ((i) << 4))
|
||||
#define USB_WINDOW_BASE(i) (0x324 + ((i) << 4))
|
||||
#define USB_IPG 0x360
|
||||
#define USB_PHY_PWR_CTRL 0x400
|
||||
#define USB_PHY_TX_CTRL 0x420
|
||||
|
|
@ -162,8 +165,30 @@ static const struct hc_driver ehci_orion_hc_driver = {
|
|||
.bus_resume = ehci_bus_resume,
|
||||
};
|
||||
|
||||
static void __init
|
||||
ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
|
||||
struct mbus_dram_target_info *dram)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
wrl(USB_WINDOW_CTRL(i), 0);
|
||||
wrl(USB_WINDOW_BASE(i), 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < dram->num_cs; i++) {
|
||||
struct mbus_dram_window *cs = dram->cs + i;
|
||||
|
||||
wrl(USB_WINDOW_CTRL(i), ((cs->size - 1) & 0xffff0000) |
|
||||
(cs->mbus_attr << 8) |
|
||||
(dram->mbus_dram_target_id << 4) | 1);
|
||||
wrl(USB_WINDOW_BASE(i), cs->base);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init ehci_orion_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct orion_ehci_data *pd = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
|
|
@ -226,6 +251,12 @@ static int __init ehci_orion_drv_probe(struct platform_device *pdev)
|
|||
ehci->is_tdi_rh_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
/*
|
||||
* (Re-)program MBUS remapping windows if we are asked to.
|
||||
*/
|
||||
if (pd != NULL && pd->dram != NULL)
|
||||
ehci_orion_conf_mbus_windows(hcd, pd->dram);
|
||||
|
||||
/*
|
||||
* setup Orion USB controller
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include <asm/irq.h>
|
||||
#include <asm/div64.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/pxa2xx-gpio.h>
|
||||
#include <asm/arch/bitfield.h>
|
||||
#include <asm/arch/pxafb.h>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue