Commit 1543966a authored by Russell King's avatar Russell King Committed by Russell King

Merge branch 'pxa-palm' into pxa-machines

Conflicts:

	drivers/mfd/Kconfig
	drivers/pcmcia/Makefile
parents 5ff7f78a 4e9687d9
...@@ -623,6 +623,12 @@ M: marek.vasut@gmail.com ...@@ -623,6 +623,12 @@ M: marek.vasut@gmail.com
W: http://hackndev.com W: http://hackndev.com
S: Maintained S: Maintained
ARM/PALMZ72 SUPPORT
P: Sergey Lapin
M: slapin@ossfans.org
W: http://hackndev.com
S: Maintained
ARM/PLEB SUPPORT ARM/PLEB SUPPORT
P: Peter Chubb P: Peter Chubb
M: pleb@gelato.unsw.edu.au M: pleb@gelato.unsw.edu.au
......
This diff is collapsed.
...@@ -288,6 +288,16 @@ config MACH_PALMTX ...@@ -288,6 +288,16 @@ config MACH_PALMTX
Say Y here if you intend to run this kernel on a Palm T|X Say Y here if you intend to run this kernel on a Palm T|X
handheld computer. handheld computer.
config MACH_PALMZ72
bool "Palm Zire 72"
default y
depends on ARCH_PXA_PALM
select PXA27x
select IWMMXT
help
Say Y here if you intend to run this kernel on Palm Zire 72
handheld computer.
config MACH_PCM990_BASEBOARD config MACH_PCM990_BASEBOARD
bool "PHYTEC PCM-990 development board" bool "PHYTEC PCM-990 development board"
select HAVE_PWM select HAVE_PWM
......
...@@ -45,6 +45,7 @@ obj-$(CONFIG_MACH_E750) += e750_lcd.o ...@@ -45,6 +45,7 @@ obj-$(CONFIG_MACH_E750) += e750_lcd.o
obj-$(CONFIG_MACH_E400) += e400_lcd.o obj-$(CONFIG_MACH_E400) += e400_lcd.o
obj-$(CONFIG_MACH_E800) += e800_lcd.o obj-$(CONFIG_MACH_E800) += e800_lcd.o
obj-$(CONFIG_MACH_PALMTX) += palmtx.o obj-$(CONFIG_MACH_PALMTX) += palmtx.o
obj-$(CONFIG_MACH_PALMZ72) += palmz72.o
ifeq ($(CONFIG_MACH_ZYLONITE),y) ifeq ($(CONFIG_MACH_ZYLONITE),y)
obj-y += zylonite.o obj-y += zylonite.o
......
/*
* GPIOs and interrupts for Palm Zire72 Handheld Computer
*
* Authors: Alex Osborne <bobofdoom@gmail.com>
* Jan Herman <2hp@seznam.cz>
* Sergey Lapin <slapin@ossfans.org>
*
* 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.
*
*/
#ifndef _INCLUDE_PALMZ72_H_
#define _INCLUDE_PALMZ72_H_
/* Power and control */
#define GPIO_NR_PALMZ72_GPIO_RESET 1
#define GPIO_NR_PALMZ72_POWER_DETECT 0
/* SD/MMC */
#define GPIO_NR_PALMZ72_SD_DETECT_N 14
#define GPIO_NR_PALMZ72_SD_POWER_N 98
#define GPIO_NR_PALMZ72_SD_RO 115
/* Touchscreen */
#define GPIO_NR_PALMZ72_WM9712_IRQ 27
/* IRDA - disable GPIO connected to SD pin of tranceiver (TFBS4710?) ? */
#define GPIO_NR_PALMZ72_IR_DISABLE 49
/* USB */
#define GPIO_NR_PALMZ72_USB_DETECT_N 15
#define GPIO_NR_PALMZ72_USB_POWER 95
#define GPIO_NR_PALMZ72_USB_PULLUP 12
/* LCD/Backlight */
#define GPIO_NR_PALMZ72_BL_POWER 20
#define GPIO_NR_PALMZ72_LCD_POWER 96
/* LED */
#define GPIO_NR_PALMZ72_LED_GREEN 88
/* Bluetooth */
#define GPIO_NR_PALMZ72_BT_POWER 17
#define GPIO_NR_PALMZ72_BT_RESET 83
/** Initial values **/
/* Battery */
#define PALMZ72_BAT_MAX_VOLTAGE 4000 /* 4.00v current voltage */
#define PALMZ72_BAT_MIN_VOLTAGE 3550 /* 3.55v critical voltage */
#define PALMZ72_BAT_MAX_CURRENT 0 /* unknokn */
#define PALMZ72_BAT_MIN_CURRENT 0 /* unknown */
#define PALMZ72_BAT_MAX_CHARGE 1 /* unknown */
#define PALMZ72_BAT_MIN_CHARGE 1 /* unknown */
#define PALMZ72_MAX_LIFE_MINS 360 /* on-life in minutes */
/* Backlight */
#define PALMZ72_MAX_INTENSITY 0xFE
#define PALMZ72_DEFAULT_INTENSITY 0x7E
#define PALMZ72_LIMIT_MASK 0x7F
#define PALMZ72_PRESCALER 0x3F
#define PALMZ72_PERIOD_NS 3500
#endif
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <linux/pda_power.h> #include <linux/pda_power.h>
#include <linux/pwm_backlight.h> #include <linux/pwm_backlight.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/wm97xx_batt.h>
#include <linux/power_supply.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
...@@ -339,6 +341,23 @@ static struct platform_device power_supply = { ...@@ -339,6 +341,23 @@ static struct platform_device power_supply = {
}, },
}; };
/******************************************************************************
* WM97xx battery
******************************************************************************/
static struct wm97xx_batt_info wm97xx_batt_pdata = {
.batt_aux = WM97XX_AUX_ID3,
.temp_aux = WM97XX_AUX_ID2,
.charge_gpio = -1,
.max_voltage = PALMTX_BAT_MAX_VOLTAGE,
.min_voltage = PALMTX_BAT_MIN_VOLTAGE,
.batt_mult = 1000,
.batt_div = 414,
.temp_mult = 1,
.temp_div = 1,
.batt_tech = POWER_SUPPLY_TECHNOLOGY_LIPO,
.batt_name = "main-batt",
};
/****************************************************************************** /******************************************************************************
* Framebuffer * Framebuffer
******************************************************************************/ ******************************************************************************/
...@@ -401,6 +420,7 @@ static void __init palmtx_init(void) ...@@ -401,6 +420,7 @@ static void __init palmtx_init(void)
pxa_set_ac97_info(NULL); pxa_set_ac97_info(NULL);
pxa_set_ficp_info(&palmtx_ficp_platform_data); pxa_set_ficp_info(&palmtx_ficp_platform_data);
pxa_set_keypad_info(&palmtx_keypad_platform_data); pxa_set_keypad_info(&palmtx_keypad_platform_data);
wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
platform_add_devices(devices, ARRAY_SIZE(devices)); platform_add_devices(devices, ARRAY_SIZE(devices));
} }
......
This diff is collapsed.
...@@ -220,6 +220,7 @@ config TOUCHSCREEN_ATMEL_TSADCC ...@@ -220,6 +220,7 @@ config TOUCHSCREEN_ATMEL_TSADCC
config TOUCHSCREEN_UCB1400 config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen" tristate "Philips UCB1400 touchscreen"
select AC97_BUS select AC97_BUS
depends on UCB1400_CORE
help help
This enables support for the Philips UCB1400 touchscreen interface. This enables support for the Philips UCB1400 touchscreen interface.
The UCB1400 is an AC97 audio codec. The touchscreen interface The UCB1400 is an AC97 audio codec. The touchscreen interface
......
This diff is collapsed.
...@@ -50,6 +50,15 @@ config HTC_PASIC3 ...@@ -50,6 +50,15 @@ config HTC_PASIC3
HTC Magician devices, respectively. Actual functionality is HTC Magician devices, respectively. Actual functionality is
handled by the leds-pasic3 and ds1wm drivers. handled by the leds-pasic3 and ds1wm drivers.
config UCB1400_CORE
tristate "Philips UCB1400 Core driver"
help
This enables support for the Philips UCB1400 core functions.
The UCB1400 is an AC97 audio codec.
To compile this driver as a module, choose M here: the
module will be called ucb1400_core.
config MFD_TMIO config MFD_TMIO
bool bool
default n default n
......
...@@ -22,3 +22,4 @@ obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o ...@@ -22,3 +22,4 @@ obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
ifeq ($(CONFIG_SA1100_ASSABET),y) ifeq ($(CONFIG_SA1100_ASSABET),y)
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
endif endif
obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
/*
* Core functions for:
* Philips UCB1400 multifunction chip
*
* Based on ucb1400_ts.c:
* Author: Nicolas Pitre
* Created: September 25, 2006
* Copyright: MontaVista Software, Inc.
*
* Spliting done by: Marek Vasut <marek.vasut@gmail.com>
* If something doesnt work and it worked before spliting, e-mail me,
* dont bother Nicolas please ;-)
*
* 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.
*
* This code is heavily based on ucb1x00-*.c copyrighted by Russell King
* covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has
* been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
*/
#include <linux/module.h>
#include <linux/ucb1400.h>
static int ucb1400_core_probe(struct device *dev)
{
int err;
struct ucb1400 *ucb;
struct ucb1400_ts ucb_ts;
struct snd_ac97 *ac97;
memset(&ucb_ts, 0, sizeof(ucb_ts));
ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL);
if (!ucb) {
err = -ENOMEM;
goto err;
}
dev_set_drvdata(dev, ucb);
ac97 = to_ac97_t(dev);
ucb_ts.id = ucb1400_reg_read(ac97, UCB_ID);
if (ucb_ts.id != UCB_ID_1400) {
err = -ENODEV;
goto err0;
}
/* TOUCHSCREEN */
ucb_ts.ac97 = ac97;
ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1);
if (!ucb->ucb1400_ts) {
err = -ENOMEM;
goto err0;
}
err = platform_device_add_data(ucb->ucb1400_ts, &ucb_ts,
sizeof(ucb_ts));
if (err)
goto err1;
err = platform_device_add(ucb->ucb1400_ts);
if (err)
goto err1;
return 0;
err1:
platform_device_put(ucb->ucb1400_ts);
err0:
kfree(ucb);
err:
return err;
}
static int ucb1400_core_remove(struct device *dev)
{
struct ucb1400 *ucb = dev_get_drvdata(dev);
platform_device_unregister(ucb->ucb1400_ts);
kfree(ucb);
return 0;
}
static struct device_driver ucb1400_core_driver = {
.name = "ucb1400_core",
.bus = &ac97_bus_type,
.probe = ucb1400_core_probe,
.remove = ucb1400_core_remove,
};
static int __init ucb1400_core_init(void)
{
return driver_register(&ucb1400_core_driver);
}
static void __exit ucb1400_core_exit(void)
{
driver_unregister(&ucb1400_core_driver);
}
module_init(ucb1400_core_init);
module_exit(ucb1400_core_exit);
MODULE_DESCRIPTION("Philips UCB1400 driver");
MODULE_LICENSE("GPL");
...@@ -74,4 +74,5 @@ pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o ...@@ -74,4 +74,5 @@ pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o
pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o
pxa2xx_cs-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps.o pxa2xx_cs-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps.o
pxa2xx_cs-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o pxa2xx_cs-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o
pxa2xx_cs-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o
/*
* linux/drivers/pcmcia/pxa2xx_palmld.c
*
* Driver for Palm LifeDrive PCMCIA
*
* Copyright (C) 2006 Alex Osborne <ato@meshy.org>
* Copyright (C) 2007-2008 Marek Vasut <marek.vasut@gmail.com>
*
* 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/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <asm/mach-types.h>
#include <mach/palmld.h>
#include "soc_common.h"
static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
int ret;
ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_POWER, "PCMCIA PWR");
if (ret)
goto err1;
ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_POWER, 0);
if (ret)
goto err2;
ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_RESET, "PCMCIA RST");
if (ret)
goto err2;
ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_RESET, 1);
if (ret)
goto err3;
ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_READY, "PCMCIA RDY");
if (ret)
goto err3;
ret = gpio_direction_input(GPIO_NR_PALMLD_PCMCIA_READY);
if (ret)
goto err4;
skt->irq = IRQ_GPIO(GPIO_NR_PALMLD_PCMCIA_READY);
return 0;
err4:
gpio_free(GPIO_NR_PALMLD_PCMCIA_READY);
err3:
gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET);
err2:
gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER);
err1:
return ret;
}
static void palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
{
gpio_free(GPIO_NR_PALMLD_PCMCIA_READY);
gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET);
gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER);
}
static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state)
{
state->detect = 1; /* always inserted */
state->ready = !!gpio_get_value(GPIO_NR_PALMLD_PCMCIA_READY);
state->bvd1 = 1;
state->bvd2 = 1;
state->wrprot = 0;
state->vs_3v = 1;
state->vs_Xv = 0;
}
static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
gpio_set_value(GPIO_NR_PALMLD_PCMCIA_POWER, 1);
gpio_set_value(GPIO_NR_PALMLD_PCMCIA_RESET,
!!(state->flags & SS_RESET));
return 0;
}
static void palmld_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
{
}
static void palmld_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
{
}
static struct pcmcia_low_level palmld_pcmcia_ops = {
.owner = THIS_MODULE,
.first = 0,
.nr = 2,
.hw_init = palmld_pcmcia_hw_init,
.hw_shutdown = palmld_pcmcia_hw_shutdown,
.socket_state = palmld_pcmcia_socket_state,
.configure_socket = palmld_pcmcia_configure_socket,
.socket_init = palmld_pcmcia_socket_init,
.socket_suspend = palmld_pcmcia_socket_suspend,
};
static struct platform_device *palmld_pcmcia_device;
static int __init palmld_pcmcia_init(void)
{
int ret;
if (!machine_is_palmld())
return -ENODEV;
palmld_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
if (!palmld_pcmcia_device)
return -ENOMEM;
ret = platform_device_add_data(palmld_pcmcia_device, &palmld_pcmcia_ops,
sizeof(palmld_pcmcia_ops));
if (!ret)
ret = platform_device_add(palmld_pcmcia_device);
if (ret)
platform_device_put(palmld_pcmcia_device);
return ret;
}
static void __exit palmld_pcmcia_exit(void)
{
platform_device_unregister(palmld_pcmcia_device);
}
module_init(palmld_pcmcia_init);
module_exit(palmld_pcmcia_exit);
MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
" Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION("PCMCIA support for Palm LifeDrive");
MODULE_ALIAS("platform:pxa2xx-pcmcia");
MODULE_LICENSE("GPL");
...@@ -56,10 +56,10 @@ config BATTERY_TOSA ...@@ -56,10 +56,10 @@ config BATTERY_TOSA
Say Y to enable support for the battery on the Sharp Zaurus Say Y to enable support for the battery on the Sharp Zaurus
SL-6000 (tosa) models. SL-6000 (tosa) models.
config BATTERY_PALMTX config BATTERY_WM97XX
tristate "Palm T|X battery" bool "WM97xx generic battery driver"
depends on MACH_PALMTX depends on TOUCHSCREEN_WM97XX
help help
Say Y to enable support for the battery in Palm T|X. Say Y to enable support for battery measured by WM97xx aux port.
endif # POWER_SUPPLY endif # POWER_SUPPLY
...@@ -21,4 +21,4 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o ...@@ -21,4 +21,4 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
obj-$(CONFIG_BATTERY_PALMTX) += palmtx_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
\ No newline at end of file
/*
* linux/drivers/power/palmtx_battery.c
*
* Battery measurement code for Palm T|X Handheld computer
*
* based on tosa_battery.c
*
* Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
*
* 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/module.h>
#include <linux/power_supply.h>
#include <linux/wm97xx.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <asm/mach-types.h>
#include <mach/palmtx.h>
static DEFINE_MUTEX(bat_lock);
static struct work_struct bat_work;
struct mutex work_lock;
int bat_status = POWER_SUPPLY_STATUS_DISCHARGING;
static unsigned long palmtx_read_bat(struct power_supply *bat_ps)
{
return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
WM97XX_AUX_ID3) * 1000 / 414;
}
static unsigned long palmtx_read_temp(struct power_supply *bat_ps)
{
return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
WM97XX_AUX_ID2);
}
static int palmtx_bat_get_property(struct power_supply *bat_ps,
enum power_supply_property psp,
union power_supply_propval *val)
{
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = bat_status;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = palmtx_read_bat(bat_ps);
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
val->intval = PALMTX_BAT_MAX_VOLTAGE;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
val->intval = PALMTX_BAT_MIN_VOLTAGE;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = palmtx_read_temp(bat_ps);
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1;
break;
default:
return -EINVAL;
}
return 0;
}
static void palmtx_bat_external_power_changed(struct power_supply *bat_ps)
{
schedule_work(&bat_work);
}
static char *status_text[] = {
[POWER_SUPPLY_STATUS_UNKNOWN] = "Unknown",
[POWER_SUPPLY_STATUS_CHARGING] = "Charging",
[POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging",
};
static void palmtx_bat_update(struct power_supply *bat_ps)
{
int old_status = bat_status;
mutex_lock(&work_lock);
bat_status = gpio_get_value(GPIO_NR_PALMTX_POWER_DETECT) ?
POWER_SUPPLY_STATUS_CHARGING :
POWER_SUPPLY_STATUS_DISCHARGING;
if (old_status != bat_status) {
pr_debug("%s %s -> %s\n", bat_ps->name,
status_text[old_status],
status_text[bat_status]);
power_supply_changed(bat_ps);
}
mutex_unlock(&work_lock);
}
static enum power_supply_property palmtx_bat_main_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_PRESENT,
};
struct power_supply bat_ps = {
.name = "main-battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = palmtx_bat_main_props,
.num_properties = ARRAY_SIZE(palmtx_bat_main_props),
.get_property = palmtx_bat_get_property,
.external_power_changed = palmtx_bat_external_power_changed,
.use_for_apm = 1,
};
static void palmtx_bat_work(struct work_struct *work)
{
palmtx_bat_update(&bat_ps);
}
#ifdef CONFIG_PM
static int palmtx_bat_suspend(struct platform_device *dev, pm_message_t state)
{
flush_scheduled_work();
return 0;
}
static int palmtx_bat_resume(struct platform_device *dev)
{
schedule_work(&bat_work);
return 0;
}
#else
#define palmtx_bat_suspend NULL
#define palmtx_bat_resume NULL
#endif
static int __devinit palmtx_bat_probe(struct platform_device *dev)
{
int ret = 0;
if (!machine_is_palmtx())
return -ENODEV;
mutex_init(&work_lock);
INIT_WORK(&bat_work, palmtx_bat_work);
ret = power_supply_register(&dev->dev, &bat_ps);
if (!ret)
schedule_work(&bat_work);
return ret;
}
static int __devexit palmtx_bat_remove(struct platform_device *dev)
{
power_supply_unregister(&bat_ps);
return 0;
}
static struct platform_driver palmtx_bat_driver = {
.driver.name = "wm97xx-battery",
.driver.owner = THIS_MODULE,
.probe = palmtx_bat_probe,
.remove = __devexit_p(palmtx_bat_remove),
.suspend = palmtx_bat_suspend,
.resume = palmtx_bat_resume,
};
static int __init palmtx_bat_init(void)
{
return platform_driver_register(&palmtx_bat_driver);
}
static void __exit palmtx_bat_exit(void)
{
platform_driver_unregister(&palmtx_bat_driver);
}
module_init(palmtx_bat_init);
module_exit(palmtx_bat_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION("Palm T|X battery driver");
/*
* linux/drivers/power/wm97xx_battery.c
*
* Battery measurement code for WM97xx
*
* based on tosa_battery.c
*
* Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
*
* 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/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/wm97xx.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/wm97xx_batt.h>
static DEFINE_MUTEX(bat_lock);
static struct work_struct bat_work;
struct mutex work_lock;
static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
static struct wm97xx_batt_info *pdata;
static enum power_supply_property *prop;
static unsigned long wm97xx_read_bat(struct power_supply *bat_ps)
{
return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
pdata->batt_aux) * pdata->batt_mult /
pdata->batt_div;
}
static unsigned long wm97xx_read_temp(struct power_supply *bat_ps)
{
return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
pdata->temp_aux) * pdata->temp_mult /
pdata->temp_div;
}
static int wm97xx_bat_get_property(struct power_supply *bat_ps,
enum power_supply_property psp,
union power_supply_propval *val)
{
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = bat_status;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = pdata->batt_tech;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
if (pdata->batt_aux >= 0)
val->intval = wm97xx_read_bat(bat_ps);
else
return -EINVAL;
break;
case POWER_SUPPLY_PROP_TEMP:
if (pdata->temp_aux >= 0)
val->intval = wm97xx_read_temp(bat_ps);
else
return -EINVAL;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
if (pdata->max_voltage >= 0)
val->intval = pdata->max_voltage;
else
return -EINVAL;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
if (pdata->min_voltage >= 0)
val->intval = pdata->min_voltage;
else
return -EINVAL;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1;
break;
default:
return -EINVAL;
}
return 0;
}
static void wm97xx_bat_external_power_changed(struct power_supply *bat_ps)
{
schedule_work(&bat_work);
}
static void wm97xx_bat_update(struct power_supply *bat_ps)
{
int old_status = bat_status;
mutex_lock(&work_lock);
bat_status = (pdata->charge_gpio >= 0) ?
(gpio_get_value(pdata->charge_gpio) ?
POWER_SUPPLY_STATUS_DISCHARGING :
POWER_SUPPLY_STATUS_CHARGING) :
POWER_SUPPLY_STATUS_UNKNOWN;
if (old_status != bat_status) {
pr_debug("%s: %i -> %i\n", bat_ps->name, old_status,
bat_status);
power_supply_changed(bat_ps);
}
mutex_unlock(&work_lock);
}
static struct power_supply bat_ps = {
.type = POWER_SUPPLY_TYPE_BATTERY,
.get_property = wm97xx_bat_get_property,
.external_power_changed = wm97xx_bat_external_power_changed,
.use_for_apm = 1,
};
static void wm97xx_bat_work(struct work_struct *work)
{
wm97xx_bat_update(&bat_ps);
}
#ifdef CONFIG_PM
static int wm97xx_bat_suspend(struct platform_device *dev, pm_message_t state)
{
flush_scheduled_work();
return 0;
}
static int wm97xx_bat_resume(struct platform_device *dev)
{
schedule_work(&bat_work);
return 0;
}
#else
#define wm97xx_bat_suspend NULL
#define wm97xx_bat_resume NULL
#endif
static int __devinit wm97xx_bat_probe(struct platform_device *dev)
{
int ret = 0;
int props = 1; /* POWER_SUPPLY_PROP_PRESENT */
int i = 0;
if (dev->id != -1)
return -EINVAL;
mutex_init(&work_lock);
if (!pdata) {
dev_err(&dev->dev, "Please use wm97xx_bat_set_pdata\n");
return -EINVAL;
}
if (pdata->charge_gpio >= 0 && gpio_is_valid(pdata->charge_gpio)) {
ret = gpio_request(pdata->charge_gpio, "BATT CHRG");
if (ret)
goto err;
ret = gpio_direction_input(pdata->charge_gpio);
if (ret)
goto err2;
props++; /* POWER_SUPPLY_PROP_STATUS */
}
if (pdata->batt_tech >= 0)
props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
if (pdata->temp_aux >= 0)
props++; /* POWER_SUPPLY_PROP_TEMP */
if (pdata->batt_aux >= 0)
props++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
if (pdata->max_voltage >= 0)
props++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
if (pdata->min_voltage >= 0)
props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
prop = kzalloc(props * sizeof(*prop), GFP_KERNEL);
if (!prop)
goto err2;
prop[i++] = POWER_SUPPLY_PROP_PRESENT;
if (pdata->charge_gpio >= 0)
prop[i++] = POWER_SUPPLY_PROP_STATUS;
if (pdata->batt_tech >= 0)
prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY;
if (pdata->temp_aux >= 0)
prop[i++] = POWER_SUPPLY_PROP_TEMP;
if (pdata->batt_aux >= 0)
prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
if (pdata->max_voltage >= 0)
prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
if (pdata->min_voltage >= 0)
prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
INIT_WORK(&bat_work, wm97xx_bat_work);
if (!pdata->batt_name) {
dev_info(&dev->dev, "Please consider setting proper battery "
"name in platform definition file, falling "
"back to name \"wm97xx-batt\"\n");
bat_ps.name = "wm97xx-batt";
} else
bat_ps.name = pdata->batt_name;
bat_ps.properties = prop;
bat_ps.num_properties = props;
ret = power_supply_register(&dev->dev, &bat_ps);
if (!ret)
schedule_work(&bat_work);
else
goto err3;
return 0;
err3:
kfree(prop);
err2:
gpio_free(pdata->charge_gpio);
err:
return ret;
}
static int __devexit wm97xx_bat_remove(struct platform_device *dev)
{
if (pdata && pdata->charge_gpio && pdata->charge_gpio >= 0)
gpio_free(pdata->charge_gpio);
flush_scheduled_work();
power_supply_unregister(&bat_ps);
kfree(prop);
return 0;
}
static struct platform_driver wm97xx_bat_driver = {
.driver = {
.name = "wm97xx-battery",
.owner = THIS_MODULE,
},
.probe = wm97xx_bat_probe,
.remove = __devexit_p(wm97xx_bat_remove),
.suspend = wm97xx_bat_suspend,
.resume = wm97xx_bat_resume,
};
static int __init wm97xx_bat_init(void)
{
return platform_driver_register(&wm97xx_bat_driver);
}
static void __exit wm97xx_bat_exit(void)
{
platform_driver_unregister(&wm97xx_bat_driver);
}
void __init wm97xx_bat_set_pdata(struct wm97xx_batt_info *data)
{
pdata = data;
}
EXPORT_SYMBOL_GPL(wm97xx_bat_set_pdata);
module_init(wm97xx_bat_init);
module_exit(wm97xx_bat_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION("WM97xx battery driver");
/*
* Register definitions and functions for:
* Philips UCB1400 driver
*
* Based on ucb1400_ts:
* Author: Nicolas Pitre
* Created: September 25, 2006
* Copyright: MontaVista Software, Inc.
*
* Spliting done by: Marek Vasut <marek.vasut@gmail.com>
* If something doesnt work and it worked before spliting, e-mail me,
* dont bother Nicolas please ;-)
*
* 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.
*
* This code is heavily based on ucb1x00-*.c copyrighted by Russell King
* covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has
* been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
*/
#ifndef _LINUX__UCB1400_H
#define _LINUX__UCB1400_H
#include <sound/ac97_codec.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
/*
* UCB1400 AC-link registers
*/
#define UCB_IO_DATA 0x5a
#define UCB_IO_DIR 0x5c
#define UCB_IE_RIS 0x5e
#define UCB_IE_FAL 0x60
#define UCB_IE_STATUS 0x62
#define UCB_IE_CLEAR 0x62
#define UCB_IE_ADC (1 << 11)
#define UCB_IE_TSPX (1 << 12)
#define UCB_TS_CR 0x64
#define UCB_TS_CR_TSMX_POW (1 << 0)
#define UCB_TS_CR_TSPX_POW (1 << 1)
#define UCB_TS_CR_TSMY_POW (1 << 2)
#define UCB_TS_CR_TSPY_POW (1 << 3)
#define UCB_TS_CR_TSMX_GND (1 << 4)
#define UCB_TS_CR_TSPX_GND (1 << 5)
#define UCB_TS_CR_TSMY_GND (1 << 6)
#define UCB_TS_CR_TSPY_GND (1 << 7)
#define UCB_TS_CR_MODE_INT (0 << 8)
#define UCB_TS_CR_MODE_PRES (1 << 8)
#define UCB_TS_CR_MODE_POS (2 << 8)
#define UCB_TS_CR_BIAS_ENA (1 << 11)
#define UCB_TS_CR_TSPX_LOW (1 << 12)
#define UCB_TS_CR_TSMX_LOW (1 << 13)
#define UCB_ADC_CR 0x66
#define UCB_ADC_SYNC_ENA (1 << 0)
#define UCB_ADC_VREFBYP_CON (1 << 1)
#define UCB_ADC_INP_TSPX (0 << 2)
#define UCB_ADC_INP_TSMX (1 << 2)
#define UCB_ADC_INP_TSPY (2 << 2)
#define UCB_ADC_INP_TSMY (3 << 2)
#define UCB_ADC_INP_AD0 (4 << 2)
#define UCB_ADC_INP_AD1 (5 << 2)
#define UCB_ADC_INP_AD2 (6 << 2)
#define UCB_ADC_INP_AD3 (7 << 2)
#define UCB_ADC_EXT_REF (1 << 5)
#define UCB_ADC_START (1 << 7)
#define UCB_ADC_ENA (1 << 15)
#define UCB_ADC_DATA 0x68
#define UCB_ADC_DAT_VALID (1 << 15)
#define UCB_ADC_DAT_MASK 0x3ff
#define UCB_ID 0x7e
#define UCB_ID_1400 0x4304
struct ucb1400_ts {
struct input_dev *ts_idev;
struct task_struct *ts_task;
int id;
wait_queue_head_t ts_wait;
unsigned int ts_restart:1;
int irq;
unsigned int irq_pending; /* not bit field shared */
struct snd_ac97 *ac97;
};
struct ucb1400 {
struct platform_device *ucb1400_ts;
};
static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg)
{
return ac97->bus->ops->read(ac97, reg);
}
static inline void ucb1400_reg_write(struct snd_ac97 *ac97, u16 reg, u16 val)
{
ac97->bus->ops->write(ac97, reg, val);
}
static inline u16 ucb1400_gpio_get_value(struct snd_ac97 *ac97, u16 gpio)
{
return ucb1400_reg_read(ac97, UCB_IO_DATA) & (1 << gpio);
}
static inline void ucb1400_gpio_set_value(struct snd_ac97 *ac97, u16 gpio,
u16 val)
{
ucb1400_reg_write(ac97, UCB_IO_DATA, val ?
ucb1400_reg_read(ac97, UCB_IO_DATA) | (1 << gpio) :
ucb1400_reg_read(ac97, UCB_IO_DATA) & ~(1 << gpio));
}
static inline u16 ucb1400_gpio_get_direction(struct snd_ac97 *ac97, u16 gpio)
{
return ucb1400_reg_read(ac97, UCB_IO_DIR) & (1 << gpio);
}
static inline void ucb1400_gpio_set_direction(struct snd_ac97 *ac97, u16 gpio,
u16 dir)
{
ucb1400_reg_write(ac97, UCB_IO_DIR, dir ?
ucb1400_reg_read(ac97, UCB_IO_DIR) | (1 << gpio) :
ucb1400_reg_read(ac97, UCB_IO_DIR) & ~(1 << gpio));
}
static inline void ucb1400_adc_enable(struct snd_ac97 *ac97)
{
ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA);
}
static unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel,
int adcsync)
{
unsigned int val;
if (adcsync)
adc_channel |= UCB_ADC_SYNC_ENA;
ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel);
ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel |
UCB_ADC_START);
while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA))
& UCB_ADC_DAT_VALID))
schedule_timeout_uninterruptible(1);
return val & UCB_ADC_DAT_MASK;
}
static inline void ucb1400_adc_disable(struct snd_ac97 *ac97)
{
ucb1400_reg_write(ac97, UCB_ADC_CR, 0);
}
#endif
#ifndef _LINUX_WM97XX_BAT_H
#define _LINUX_WM97XX_BAT_H
#include <linux/wm97xx.h>
struct wm97xx_batt_info {
int batt_aux;
int temp_aux;
int charge_gpio;
int min_voltage;
int max_voltage;
int batt_div;
int batt_mult;
int temp_div;
int temp_mult;
int batt_tech;
char *batt_name;
};
#ifdef CONFIG_BATTERY_WM97XX
void __init wm97xx_bat_set_pdata(struct wm97xx_batt_info *data);
#else
static inline void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data) {}
#endif
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment