aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2009-12-06 11:53:09 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-12-06 11:53:12 -0500
commitba71e17269633ea36e776d744d5cc0fcb5a41f93 (patch)
tree0a51c86e5c218ac2ae74ff8193880a64053a77bc /drivers
parent729fae44dd8332cbf5b9d05a9af17a7455e165b2 (diff)
parent9823b2d0f9547742fc40857f9ef153d6956266f2 (diff)
Merge branch 'for-lak' of git://git.linuxtogo.org/home/thesing/collie into sa1100
Diffstat (limited to 'drivers')
-rw-r--r--drivers/leds/leds-locomo.c2
-rw-r--r--drivers/mfd/mcp-core.c2
-rw-r--r--drivers/mfd/mcp-sa11x0.c3
-rw-r--r--drivers/mfd/mcp.h66
-rw-r--r--drivers/mfd/ucb1x00-assabet.c2
-rw-r--r--drivers/mfd/ucb1x00-core.c89
-rw-r--r--drivers/mfd/ucb1x00-ts.c2
-rw-r--r--drivers/mfd/ucb1x00.h255
-rw-r--r--drivers/power/Kconfig7
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/collie_battery.c418
11 files changed, 518 insertions, 329 deletions
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 5d91362e3066..1f7c10f6b7f2 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -44,7 +44,7 @@ static void locomoled_brightness_set1(struct led_classdev *led_cdev,
44 44
45static struct led_classdev locomo_led0 = { 45static struct led_classdev locomo_led0 = {
46 .name = "locomo:amber:charge", 46 .name = "locomo:amber:charge",
47 .default_trigger = "sharpsl-charge", 47 .default_trigger = "main-battery-charging",
48 .brightness_set = locomoled_brightness_set0, 48 .brightness_set = locomoled_brightness_set0,
49}; 49};
50 50
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 57271cb3b316..84815f9ef636 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -17,11 +17,11 @@
17#include <linux/device.h> 17#include <linux/device.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/string.h> 19#include <linux/string.h>
20#include <linux/mfd/mcp.h>
20 21
21#include <mach/dma.h> 22#include <mach/dma.h>
22#include <asm/system.h> 23#include <asm/system.h>
23 24
24#include "mcp.h"
25 25
26#define to_mcp(d) container_of(d, struct mcp, attached_device) 26#define to_mcp(d) container_of(d, struct mcp, attached_device)
27#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) 27#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 62b32dabf629..258427232728 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -19,6 +19,7 @@
19#include <linux/spinlock.h> 19#include <linux/spinlock.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/platform_device.h> 21#include <linux/platform_device.h>
22#include <linux/mfd/mcp.h>
22 23
23#include <mach/dma.h> 24#include <mach/dma.h>
24#include <mach/hardware.h> 25#include <mach/hardware.h>
@@ -28,7 +29,6 @@
28 29
29#include <mach/assabet.h> 30#include <mach/assabet.h>
30 31
31#include "mcp.h"
32 32
33struct mcp_sa11x0 { 33struct mcp_sa11x0 {
34 u32 mccr0; 34 u32 mccr0;
@@ -163,6 +163,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
163 mcp->dma_audio_wr = DMA_Ser4MCP0Wr; 163 mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
164 mcp->dma_telco_rd = DMA_Ser4MCP1Rd; 164 mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
165 mcp->dma_telco_wr = DMA_Ser4MCP1Wr; 165 mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
166 mcp->gpio_base = data->gpio_base;
166 167
167 platform_set_drvdata(pdev, mcp); 168 platform_set_drvdata(pdev, mcp);
168 169
diff --git a/drivers/mfd/mcp.h b/drivers/mfd/mcp.h
deleted file mode 100644
index c093a93b8808..000000000000
--- a/drivers/mfd/mcp.h
+++ /dev/null
@@ -1,66 +0,0 @@
1/*
2 * linux/drivers/mfd/mcp.h
3 *
4 * Copyright (C) 2001 Russell King, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License.
9 */
10#ifndef MCP_H
11#define MCP_H
12
13struct mcp_ops;
14
15struct mcp {
16 struct module *owner;
17 struct mcp_ops *ops;
18 spinlock_t lock;
19 int use_count;
20 unsigned int sclk_rate;
21 unsigned int rw_timeout;
22 dma_device_t dma_audio_rd;
23 dma_device_t dma_audio_wr;
24 dma_device_t dma_telco_rd;
25 dma_device_t dma_telco_wr;
26 struct device attached_device;
27};
28
29struct mcp_ops {
30 void (*set_telecom_divisor)(struct mcp *, unsigned int);
31 void (*set_audio_divisor)(struct mcp *, unsigned int);
32 void (*reg_write)(struct mcp *, unsigned int, unsigned int);
33 unsigned int (*reg_read)(struct mcp *, unsigned int);
34 void (*enable)(struct mcp *);
35 void (*disable)(struct mcp *);
36};
37
38void mcp_set_telecom_divisor(struct mcp *, unsigned int);
39void mcp_set_audio_divisor(struct mcp *, unsigned int);
40void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
41unsigned int mcp_reg_read(struct mcp *, unsigned int);
42void mcp_enable(struct mcp *);
43void mcp_disable(struct mcp *);
44#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
45
46struct mcp *mcp_host_alloc(struct device *, size_t);
47int mcp_host_register(struct mcp *);
48void mcp_host_unregister(struct mcp *);
49
50struct mcp_driver {
51 struct device_driver drv;
52 int (*probe)(struct mcp *);
53 void (*remove)(struct mcp *);
54 int (*suspend)(struct mcp *, pm_message_t);
55 int (*resume)(struct mcp *);
56};
57
58int mcp_driver_register(struct mcp_driver *);
59void mcp_driver_unregister(struct mcp_driver *);
60
61#define mcp_get_drvdata(mcp) dev_get_drvdata(&(mcp)->attached_device)
62#define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d)
63
64#define mcp_priv(mcp) ((void *)((mcp)+1))
65
66#endif
diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index 86fed4870f93..cea9da60850d 100644
--- a/drivers/mfd/ucb1x00-assabet.c
+++ b/drivers/mfd/ucb1x00-assabet.c
@@ -14,10 +14,10 @@
14#include <linux/fs.h> 14#include <linux/fs.h>
15#include <linux/proc_fs.h> 15#include <linux/proc_fs.h>
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/mfd/ucb1x00.h>
17 18
18#include <mach/dma.h> 19#include <mach/dma.h>
19 20
20#include "ucb1x00.h"
21 21
22#define UCB1X00_ATTR(name,input)\ 22#define UCB1X00_ATTR(name,input)\
23static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ 23static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 60c3988f3cf3..252b74188ec2 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -25,12 +25,12 @@
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/mutex.h> 27#include <linux/mutex.h>
28#include <linux/mfd/ucb1x00.h>
29#include <linux/gpio.h>
28 30
29#include <mach/dma.h> 31#include <mach/dma.h>
30#include <mach/hardware.h> 32#include <mach/hardware.h>
31 33
32#include "ucb1x00.h"
33
34static DEFINE_MUTEX(ucb1x00_mutex); 34static DEFINE_MUTEX(ucb1x00_mutex);
35static LIST_HEAD(ucb1x00_drivers); 35static LIST_HEAD(ucb1x00_drivers);
36static LIST_HEAD(ucb1x00_devices); 36static LIST_HEAD(ucb1x00_devices);
@@ -108,6 +108,60 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
108 return ucb1x00_reg_read(ucb, UCB_IO_DATA); 108 return ucb1x00_reg_read(ucb, UCB_IO_DATA);
109} 109}
110 110
111static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
112{
113 struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
114 unsigned long flags;
115
116 spin_lock_irqsave(&ucb->io_lock, flags);
117 if (value)
118 ucb->io_out |= 1 << offset;
119 else
120 ucb->io_out &= ~(1 << offset);
121
122 ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
123 spin_unlock_irqrestore(&ucb->io_lock, flags);
124}
125
126static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
127{
128 struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
129 return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
130}
131
132static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
133{
134 struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
135 unsigned long flags;
136
137 spin_lock_irqsave(&ucb->io_lock, flags);
138 ucb->io_dir &= ~(1 << offset);
139 ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
140 spin_unlock_irqrestore(&ucb->io_lock, flags);
141
142 return 0;
143}
144
145static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
146 , int value)
147{
148 struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
149 unsigned long flags;
150
151 spin_lock_irqsave(&ucb->io_lock, flags);
152 ucb->io_dir |= (1 << offset);
153 ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
154
155 if (value)
156 ucb->io_out |= 1 << offset;
157 else
158 ucb->io_out &= ~(1 << offset);
159 ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
160 spin_unlock_irqrestore(&ucb->io_lock, flags);
161
162 return 0;
163}
164
111/* 165/*
112 * UCB1300 data sheet says we must: 166 * UCB1300 data sheet says we must:
113 * 1. enable ADC => 5us (including reference startup time) 167 * 1. enable ADC => 5us (including reference startup time)
@@ -476,6 +530,7 @@ static int ucb1x00_probe(struct mcp *mcp)
476 struct ucb1x00_driver *drv; 530 struct ucb1x00_driver *drv;
477 unsigned int id; 531 unsigned int id;
478 int ret = -ENODEV; 532 int ret = -ENODEV;
533 int temp;
479 534
480 mcp_enable(mcp); 535 mcp_enable(mcp);
481 id = mcp_reg_read(mcp, UCB_ID); 536 id = mcp_reg_read(mcp, UCB_ID);
@@ -508,12 +563,27 @@ static int ucb1x00_probe(struct mcp *mcp)
508 goto err_free; 563 goto err_free;
509 } 564 }
510 565
566 ucb->gpio.base = -1;
567 if (mcp->gpio_base != 0) {
568 ucb->gpio.label = dev_name(&ucb->dev);
569 ucb->gpio.base = mcp->gpio_base;
570 ucb->gpio.ngpio = 10;
571 ucb->gpio.set = ucb1x00_gpio_set;
572 ucb->gpio.get = ucb1x00_gpio_get;
573 ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
574 ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
575 ret = gpiochip_add(&ucb->gpio);
576 if (ret)
577 goto err_free;
578 } else
579 dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
580
511 ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, 581 ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
512 "UCB1x00", ucb); 582 "UCB1x00", ucb);
513 if (ret) { 583 if (ret) {
514 printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", 584 printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
515 ucb->irq, ret); 585 ucb->irq, ret);
516 goto err_free; 586 goto err_gpio;
517 } 587 }
518 588
519 mcp_set_drvdata(mcp, ucb); 589 mcp_set_drvdata(mcp, ucb);
@@ -522,6 +592,7 @@ static int ucb1x00_probe(struct mcp *mcp)
522 if (ret) 592 if (ret)
523 goto err_irq; 593 goto err_irq;
524 594
595
525 INIT_LIST_HEAD(&ucb->devs); 596 INIT_LIST_HEAD(&ucb->devs);
526 mutex_lock(&ucb1x00_mutex); 597 mutex_lock(&ucb1x00_mutex);
527 list_add(&ucb->node, &ucb1x00_devices); 598 list_add(&ucb->node, &ucb1x00_devices);
@@ -529,10 +600,14 @@ static int ucb1x00_probe(struct mcp *mcp)
529 ucb1x00_add_dev(ucb, drv); 600 ucb1x00_add_dev(ucb, drv);
530 } 601 }
531 mutex_unlock(&ucb1x00_mutex); 602 mutex_unlock(&ucb1x00_mutex);
603
532 goto out; 604 goto out;
533 605
534 err_irq: 606 err_irq:
535 free_irq(ucb->irq, ucb); 607 free_irq(ucb->irq, ucb);
608 err_gpio:
609 if (ucb->gpio.base != -1)
610 temp = gpiochip_remove(&ucb->gpio);
536 err_free: 611 err_free:
537 kfree(ucb); 612 kfree(ucb);
538 err_disable: 613 err_disable:
@@ -545,6 +620,7 @@ static void ucb1x00_remove(struct mcp *mcp)
545{ 620{
546 struct ucb1x00 *ucb = mcp_get_drvdata(mcp); 621 struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
547 struct list_head *l, *n; 622 struct list_head *l, *n;
623 int ret;
548 624
549 mutex_lock(&ucb1x00_mutex); 625 mutex_lock(&ucb1x00_mutex);
550 list_del(&ucb->node); 626 list_del(&ucb->node);
@@ -554,6 +630,12 @@ static void ucb1x00_remove(struct mcp *mcp)
554 } 630 }
555 mutex_unlock(&ucb1x00_mutex); 631 mutex_unlock(&ucb1x00_mutex);
556 632
633 if (ucb->gpio.base != -1) {
634 ret = gpiochip_remove(&ucb->gpio);
635 if (ret)
636 dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
637 }
638
557 free_irq(ucb->irq, ucb); 639 free_irq(ucb->irq, ucb);
558 device_unregister(&ucb->dev); 640 device_unregister(&ucb->dev);
559} 641}
@@ -604,6 +686,7 @@ static int ucb1x00_resume(struct mcp *mcp)
604 struct ucb1x00 *ucb = mcp_get_drvdata(mcp); 686 struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
605 struct ucb1x00_dev *dev; 687 struct ucb1x00_dev *dev;
606 688
689 ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
607 mutex_lock(&ucb1x00_mutex); 690 mutex_lock(&ucb1x00_mutex);
608 list_for_each_entry(dev, &ucb->devs, dev_node) { 691 list_for_each_entry(dev, &ucb->devs, dev_node) {
609 if (dev->drv->resume) 692 if (dev->drv->resume)
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 61b7d3eb9a2f..000cb414a78a 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -30,12 +30,12 @@
30#include <linux/freezer.h> 30#include <linux/freezer.h>
31#include <linux/slab.h> 31#include <linux/slab.h>
32#include <linux/kthread.h> 32#include <linux/kthread.h>
33#include <linux/mfd/ucb1x00.h>
33 34
34#include <mach/dma.h> 35#include <mach/dma.h>
35#include <mach/collie.h> 36#include <mach/collie.h>
36#include <asm/mach-types.h> 37#include <asm/mach-types.h>
37 38
38#include "ucb1x00.h"
39 39
40 40
41struct ucb1x00_ts { 41struct ucb1x00_ts {
diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h
deleted file mode 100644
index a8ad8a0ed5db..000000000000
--- a/drivers/mfd/ucb1x00.h
+++ /dev/null
@@ -1,255 +0,0 @@
1/*
2 * linux/drivers/mfd/ucb1x00.h
3 *
4 * Copyright (C) 2001 Russell King, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License.
9 */
10#ifndef UCB1200_H
11#define UCB1200_H
12
13#define UCB_IO_DATA 0x00
14#define UCB_IO_DIR 0x01
15
16#define UCB_IO_0 (1 << 0)
17#define UCB_IO_1 (1 << 1)
18#define UCB_IO_2 (1 << 2)
19#define UCB_IO_3 (1 << 3)
20#define UCB_IO_4 (1 << 4)
21#define UCB_IO_5 (1 << 5)
22#define UCB_IO_6 (1 << 6)
23#define UCB_IO_7 (1 << 7)
24#define UCB_IO_8 (1 << 8)
25#define UCB_IO_9 (1 << 9)
26
27#define UCB_IE_RIS 0x02
28#define UCB_IE_FAL 0x03
29#define UCB_IE_STATUS 0x04
30#define UCB_IE_CLEAR 0x04
31#define UCB_IE_ADC (1 << 11)
32#define UCB_IE_TSPX (1 << 12)
33#define UCB_IE_TSMX (1 << 13)
34#define UCB_IE_TCLIP (1 << 14)
35#define UCB_IE_ACLIP (1 << 15)
36
37#define UCB_IRQ_TSPX 12
38
39#define UCB_TC_A 0x05
40#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */
41#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */
42
43#define UCB_TC_B 0x06
44#define UCB_TC_B_VOICE_ENA (1 << 3)
45#define UCB_TC_B_CLIP (1 << 4)
46#define UCB_TC_B_ATT (1 << 6)
47#define UCB_TC_B_SIDE_ENA (1 << 11)
48#define UCB_TC_B_MUTE (1 << 13)
49#define UCB_TC_B_IN_ENA (1 << 14)
50#define UCB_TC_B_OUT_ENA (1 << 15)
51
52#define UCB_AC_A 0x07
53#define UCB_AC_B 0x08
54#define UCB_AC_B_LOOP (1 << 8)
55#define UCB_AC_B_MUTE (1 << 13)
56#define UCB_AC_B_IN_ENA (1 << 14)
57#define UCB_AC_B_OUT_ENA (1 << 15)
58
59#define UCB_TS_CR 0x09
60#define UCB_TS_CR_TSMX_POW (1 << 0)
61#define UCB_TS_CR_TSPX_POW (1 << 1)
62#define UCB_TS_CR_TSMY_POW (1 << 2)
63#define UCB_TS_CR_TSPY_POW (1 << 3)
64#define UCB_TS_CR_TSMX_GND (1 << 4)
65#define UCB_TS_CR_TSPX_GND (1 << 5)
66#define UCB_TS_CR_TSMY_GND (1 << 6)
67#define UCB_TS_CR_TSPY_GND (1 << 7)
68#define UCB_TS_CR_MODE_INT (0 << 8)
69#define UCB_TS_CR_MODE_PRES (1 << 8)
70#define UCB_TS_CR_MODE_POS (2 << 8)
71#define UCB_TS_CR_BIAS_ENA (1 << 11)
72#define UCB_TS_CR_TSPX_LOW (1 << 12)
73#define UCB_TS_CR_TSMX_LOW (1 << 13)
74
75#define UCB_ADC_CR 0x0a
76#define UCB_ADC_SYNC_ENA (1 << 0)
77#define UCB_ADC_VREFBYP_CON (1 << 1)
78#define UCB_ADC_INP_TSPX (0 << 2)
79#define UCB_ADC_INP_TSMX (1 << 2)
80#define UCB_ADC_INP_TSPY (2 << 2)
81#define UCB_ADC_INP_TSMY (3 << 2)
82#define UCB_ADC_INP_AD0 (4 << 2)
83#define UCB_ADC_INP_AD1 (5 << 2)
84#define UCB_ADC_INP_AD2 (6 << 2)
85#define UCB_ADC_INP_AD3 (7 << 2)
86#define UCB_ADC_EXT_REF (1 << 5)
87#define UCB_ADC_START (1 << 7)
88#define UCB_ADC_ENA (1 << 15)
89
90#define UCB_ADC_DATA 0x0b
91#define UCB_ADC_DAT_VAL (1 << 15)
92#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5)
93
94#define UCB_ID 0x0c
95#define UCB_ID_1200 0x1004
96#define UCB_ID_1300 0x1005
97#define UCB_ID_TC35143 0x9712
98
99#define UCB_MODE 0x0d
100#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
101#define UCB_MODE_AUD_OFF_CAN (1 << 13)
102
103#include "mcp.h"
104
105struct ucb1x00_irq {
106 void *devid;
107 void (*fn)(int, void *);
108};
109
110struct ucb1x00 {
111 spinlock_t lock;
112 struct mcp *mcp;
113 unsigned int irq;
114 struct semaphore adc_sem;
115 spinlock_t io_lock;
116 u16 id;
117 u16 io_dir;
118 u16 io_out;
119 u16 adc_cr;
120 u16 irq_fal_enbl;
121 u16 irq_ris_enbl;
122 struct ucb1x00_irq irq_handler[16];
123 struct device dev;
124 struct list_head node;
125 struct list_head devs;
126};
127
128struct ucb1x00_driver;
129
130struct ucb1x00_dev {
131 struct list_head dev_node;
132 struct list_head drv_node;
133 struct ucb1x00 *ucb;
134 struct ucb1x00_driver *drv;
135 void *priv;
136};
137
138struct ucb1x00_driver {
139 struct list_head node;
140 struct list_head devs;
141 int (*add)(struct ucb1x00_dev *dev);
142 void (*remove)(struct ucb1x00_dev *dev);
143 int (*suspend)(struct ucb1x00_dev *dev, pm_message_t state);
144 int (*resume)(struct ucb1x00_dev *dev);
145};
146
147#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, dev)
148
149int ucb1x00_register_driver(struct ucb1x00_driver *);
150void ucb1x00_unregister_driver(struct ucb1x00_driver *);
151
152/**
153 * ucb1x00_clkrate - return the UCB1x00 SIB clock rate
154 * @ucb: UCB1x00 structure describing chip
155 *
156 * Return the SIB clock rate in Hz.
157 */
158static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
159{
160 return mcp_get_sclk_rate(ucb->mcp);
161}
162
163/**
164 * ucb1x00_enable - enable the UCB1x00 SIB clock
165 * @ucb: UCB1x00 structure describing chip
166 *
167 * Enable the SIB clock. This can be called multiple times.
168 */
169static inline void ucb1x00_enable(struct ucb1x00 *ucb)
170{
171 mcp_enable(ucb->mcp);
172}
173
174/**
175 * ucb1x00_disable - disable the UCB1x00 SIB clock
176 * @ucb: UCB1x00 structure describing chip
177 *
178 * Disable the SIB clock. The SIB clock will only be disabled
179 * when the number of ucb1x00_enable calls match the number of
180 * ucb1x00_disable calls.
181 */
182static inline void ucb1x00_disable(struct ucb1x00 *ucb)
183{
184 mcp_disable(ucb->mcp);
185}
186
187/**
188 * ucb1x00_reg_write - write a UCB1x00 register
189 * @ucb: UCB1x00 structure describing chip
190 * @reg: UCB1x00 4-bit register index to write
191 * @val: UCB1x00 16-bit value to write
192 *
193 * Write the UCB1x00 register @reg with value @val. The SIB
194 * clock must be running for this function to return.
195 */
196static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
197{
198 mcp_reg_write(ucb->mcp, reg, val);
199}
200
201/**
202 * ucb1x00_reg_read - read a UCB1x00 register
203 * @ucb: UCB1x00 structure describing chip
204 * @reg: UCB1x00 4-bit register index to write
205 *
206 * Read the UCB1x00 register @reg and return its value. The SIB
207 * clock must be running for this function to return.
208 */
209static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
210{
211 return mcp_reg_read(ucb->mcp, reg);
212}
213/**
214 * ucb1x00_set_audio_divisor -
215 * @ucb: UCB1x00 structure describing chip
216 * @div: SIB clock divisor
217 */
218static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
219{
220 mcp_set_audio_divisor(ucb->mcp, div);
221}
222
223/**
224 * ucb1x00_set_telecom_divisor -
225 * @ucb: UCB1x00 structure describing chip
226 * @div: SIB clock divisor
227 */
228static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
229{
230 mcp_set_telecom_divisor(ucb->mcp, div);
231}
232
233void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
234void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
235unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
236
237#define UCB_NOSYNC (0)
238#define UCB_SYNC (1)
239
240unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
241void ucb1x00_adc_enable(struct ucb1x00 *ucb);
242void ucb1x00_adc_disable(struct ucb1x00 *ucb);
243
244/*
245 * Which edges of the IRQ do you want to control today?
246 */
247#define UCB_RISING (1 << 0)
248#define UCB_FALLING (1 << 1)
249
250int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
251void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
252void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
253int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
254
255#endif
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index cea6cef27e89..118674925516 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -77,6 +77,13 @@ config BATTERY_TOSA
77 Say Y to enable support for the battery on the Sharp Zaurus 77 Say Y to enable support for the battery on the Sharp Zaurus
78 SL-6000 (tosa) models. 78 SL-6000 (tosa) models.
79 79
80config BATTERY_COLLIE
81 tristate "Sharp SL-5500 (collie) battery"
82 depends on SA1100_COLLIE && MCP_UCB1200
83 help
84 Say Y to enable support for the battery on the Sharp Zaurus
85 SL-5500 (collie) models.
86
80config BATTERY_WM97XX 87config BATTERY_WM97XX
81 bool "WM97xx generic battery driver" 88 bool "WM97xx generic battery driver"
82 depends on TOUCHSCREEN_WM97XX=y 89 depends on TOUCHSCREEN_WM97XX=y
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index b96f29d91c28..356cdfd3c8b2 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
24obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o 24obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
25obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o 25obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
26obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o 26obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
27obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
27obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o 28obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
28obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o 29obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
29obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o 30obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
new file mode 100644
index 000000000000..039f41ae217d
--- /dev/null
+++ b/drivers/power/collie_battery.c
@@ -0,0 +1,418 @@
1/*
2 * Battery and Power Management code for the Sharp SL-5x00
3 *
4 * Copyright (C) 2009 Thomas Kunze
5 *
6 * based on tosa_battery.c
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/power_supply.h>
16#include <linux/delay.h>
17#include <linux/spinlock.h>
18#include <linux/interrupt.h>
19#include <linux/gpio.h>
20#include <linux/mfd/ucb1x00.h>
21
22#include <asm/mach/sharpsl_param.h>
23#include <asm/mach-types.h>
24#include <mach/collie.h>
25
26static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
27static struct work_struct bat_work;
28static struct ucb1x00 *ucb;
29
30struct collie_bat {
31 int status;
32 struct power_supply psy;
33 int full_chrg;
34
35 struct mutex work_lock; /* protects data */
36
37 bool (*is_present)(struct collie_bat *bat);
38 int gpio_full;
39 int gpio_charge_on;
40
41 int technology;
42
43 int gpio_bat;
44 int adc_bat;
45 int adc_bat_divider;
46 int bat_max;
47 int bat_min;
48
49 int gpio_temp;
50 int adc_temp;
51 int adc_temp_divider;
52};
53
54static struct collie_bat collie_bat_main;
55
56static unsigned long collie_read_bat(struct collie_bat *bat)
57{
58 unsigned long value = 0;
59
60 if (bat->gpio_bat < 0 || bat->adc_bat < 0)
61 return 0;
62 mutex_lock(&bat_lock);
63 gpio_set_value(bat->gpio_bat, 1);
64 msleep(5);
65 ucb1x00_adc_enable(ucb);
66 value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC);
67 ucb1x00_adc_disable(ucb);
68 gpio_set_value(bat->gpio_bat, 0);
69 mutex_unlock(&bat_lock);
70 value = value * 1000000 / bat->adc_bat_divider;
71
72 return value;
73}
74
75static unsigned long collie_read_temp(struct collie_bat *bat)
76{
77 unsigned long value = 0;
78 if (bat->gpio_temp < 0 || bat->adc_temp < 0)
79 return 0;
80
81 mutex_lock(&bat_lock);
82 gpio_set_value(bat->gpio_temp, 1);
83 msleep(5);
84 ucb1x00_adc_enable(ucb);
85 value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC);
86 ucb1x00_adc_disable(ucb);
87 gpio_set_value(bat->gpio_temp, 0);
88 mutex_unlock(&bat_lock);
89
90 value = value * 10000 / bat->adc_temp_divider;
91
92 return value;
93}
94
95static int collie_bat_get_property(struct power_supply *psy,
96 enum power_supply_property psp,
97 union power_supply_propval *val)
98{
99 int ret = 0;
100 struct collie_bat *bat = container_of(psy, struct collie_bat, psy);
101
102 if (bat->is_present && !bat->is_present(bat)
103 && psp != POWER_SUPPLY_PROP_PRESENT) {
104 return -ENODEV;
105 }
106
107 switch (psp) {
108 case POWER_SUPPLY_PROP_STATUS:
109 val->intval = bat->status;
110 break;
111 case POWER_SUPPLY_PROP_TECHNOLOGY:
112 val->intval = bat->technology;
113 break;
114 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
115 val->intval = collie_read_bat(bat);
116 break;
117 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
118 if (bat->full_chrg == -1)
119 val->intval = bat->bat_max;
120 else
121 val->intval = bat->full_chrg;
122 break;
123 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
124 val->intval = bat->bat_max;
125 break;
126 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
127 val->intval = bat->bat_min;
128 break;
129 case POWER_SUPPLY_PROP_TEMP:
130 val->intval = collie_read_temp(bat);
131 break;
132 case POWER_SUPPLY_PROP_PRESENT:
133 val->intval = bat->is_present ? bat->is_present(bat) : 1;
134 break;
135 default:
136 ret = -EINVAL;
137 break;
138 }
139 return ret;
140}
141
142static void collie_bat_external_power_changed(struct power_supply *psy)
143{
144 schedule_work(&bat_work);
145}
146
147static irqreturn_t collie_bat_gpio_isr(int irq, void *data)
148{
149 pr_info("collie_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
150 schedule_work(&bat_work);
151 return IRQ_HANDLED;
152}
153
154static void collie_bat_update(struct collie_bat *bat)
155{
156 int old;
157 struct power_supply *psy = &bat->psy;
158
159 mutex_lock(&bat->work_lock);
160
161 old = bat->status;
162
163 if (bat->is_present && !bat->is_present(bat)) {
164 printk(KERN_NOTICE "%s not present\n", psy->name);
165 bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
166 bat->full_chrg = -1;
167 } else if (power_supply_am_i_supplied(psy)) {
168 if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) {
169 gpio_set_value(bat->gpio_charge_on, 1);
170 mdelay(15);
171 }
172
173 if (gpio_get_value(bat->gpio_full)) {
174 if (old == POWER_SUPPLY_STATUS_CHARGING ||
175 bat->full_chrg == -1)
176 bat->full_chrg = collie_read_bat(bat);
177
178 gpio_set_value(bat->gpio_charge_on, 0);
179 bat->status = POWER_SUPPLY_STATUS_FULL;
180 } else {
181 gpio_set_value(bat->gpio_charge_on, 1);
182 bat->status = POWER_SUPPLY_STATUS_CHARGING;
183 }
184 } else {
185 gpio_set_value(bat->gpio_charge_on, 0);
186 bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
187 }
188
189 if (old != bat->status)
190 power_supply_changed(psy);
191
192 mutex_unlock(&bat->work_lock);
193}
194
195static void collie_bat_work(struct work_struct *work)
196{
197 collie_bat_update(&collie_bat_main);
198}
199
200
201static enum power_supply_property collie_bat_main_props[] = {
202 POWER_SUPPLY_PROP_STATUS,
203 POWER_SUPPLY_PROP_TECHNOLOGY,
204 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
205 POWER_SUPPLY_PROP_VOLTAGE_NOW,
206 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
207 POWER_SUPPLY_PROP_VOLTAGE_MAX,
208 POWER_SUPPLY_PROP_PRESENT,
209 POWER_SUPPLY_PROP_TEMP,
210};
211
212static enum power_supply_property collie_bat_bu_props[] = {
213 POWER_SUPPLY_PROP_STATUS,
214 POWER_SUPPLY_PROP_TECHNOLOGY,
215 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
216 POWER_SUPPLY_PROP_VOLTAGE_NOW,
217 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
218 POWER_SUPPLY_PROP_VOLTAGE_MAX,
219 POWER_SUPPLY_PROP_PRESENT,
220};
221
222static struct collie_bat collie_bat_main = {
223 .status = POWER_SUPPLY_STATUS_DISCHARGING,
224 .full_chrg = -1,
225 .psy = {
226 .name = "main-battery",
227 .type = POWER_SUPPLY_TYPE_BATTERY,
228 .properties = collie_bat_main_props,
229 .num_properties = ARRAY_SIZE(collie_bat_main_props),
230 .get_property = collie_bat_get_property,
231 .external_power_changed = collie_bat_external_power_changed,
232 .use_for_apm = 1,
233 },
234
235 .gpio_full = COLLIE_GPIO_CO,
236 .gpio_charge_on = COLLIE_GPIO_CHARGE_ON,
237
238 .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
239
240 .gpio_bat = COLLIE_GPIO_MBAT_ON,
241 .adc_bat = UCB_ADC_INP_AD1,
242 .adc_bat_divider = 155,
243 .bat_max = 4310000,
244 .bat_min = 1551 * 1000000 / 414,
245
246 .gpio_temp = COLLIE_GPIO_TMP_ON,
247 .adc_temp = UCB_ADC_INP_AD0,
248 .adc_temp_divider = 10000,
249};
250
251static struct collie_bat collie_bat_bu = {
252 .status = POWER_SUPPLY_STATUS_UNKNOWN,
253 .full_chrg = -1,
254
255 .psy = {
256 .name = "backup-battery",
257 .type = POWER_SUPPLY_TYPE_BATTERY,
258 .properties = collie_bat_bu_props,
259 .num_properties = ARRAY_SIZE(collie_bat_bu_props),
260 .get_property = collie_bat_get_property,
261 .external_power_changed = collie_bat_external_power_changed,
262 },
263
264 .gpio_full = -1,
265 .gpio_charge_on = -1,
266
267 .technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
268
269 .gpio_bat = COLLIE_GPIO_BBAT_ON,
270 .adc_bat = UCB_ADC_INP_AD1,
271 .adc_bat_divider = 155,
272 .bat_max = 3000000,
273 .bat_min = 1900000,
274
275 .gpio_temp = -1,
276 .adc_temp = -1,
277 .adc_temp_divider = -1,
278};
279
280static struct {
281 int gpio;
282 char *name;
283 bool output;
284 int value;
285} gpios[] = {
286 { COLLIE_GPIO_CO, "main battery full", 0, 0 },
287 { COLLIE_GPIO_MAIN_BAT_LOW, "main battery low", 0, 0 },
288 { COLLIE_GPIO_CHARGE_ON, "main charge on", 1, 0 },
289 { COLLIE_GPIO_MBAT_ON, "main battery", 1, 0 },
290 { COLLIE_GPIO_TMP_ON, "main battery temp", 1, 0 },
291 { COLLIE_GPIO_BBAT_ON, "backup battery", 1, 0 },
292};
293
294#ifdef CONFIG_PM
295static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
296{
297 /* flush all pending status updates */
298 flush_scheduled_work();
299 return 0;
300}
301
302static int collie_bat_resume(struct ucb1x00_dev *dev)
303{
304 /* things may have changed while we were away */
305 schedule_work(&bat_work);
306 return 0;
307}
308#else
309#define collie_bat_suspend NULL
310#define collie_bat_resume NULL
311#endif
312
313static int __devinit collie_bat_probe(struct ucb1x00_dev *dev)
314{
315 int ret;
316 int i;
317
318 if (!machine_is_collie())
319 return -ENODEV;
320
321 ucb = dev->ucb;
322
323 for (i = 0; i < ARRAY_SIZE(gpios); i++) {
324 ret = gpio_request(gpios[i].gpio, gpios[i].name);
325 if (ret) {
326 i--;
327 goto err_gpio;
328 }
329
330 if (gpios[i].output)
331 ret = gpio_direction_output(gpios[i].gpio,
332 gpios[i].value);
333 else
334 ret = gpio_direction_input(gpios[i].gpio);
335
336 if (ret)
337 goto err_gpio;
338 }
339
340 mutex_init(&collie_bat_main.work_lock);
341
342 INIT_WORK(&bat_work, collie_bat_work);
343
344 ret = power_supply_register(&dev->ucb->dev, &collie_bat_main.psy);
345 if (ret)
346 goto err_psy_reg_main;
347 ret = power_supply_register(&dev->ucb->dev, &collie_bat_bu.psy);
348 if (ret)
349 goto err_psy_reg_bu;
350
351 ret = request_irq(gpio_to_irq(COLLIE_GPIO_CO),
352 collie_bat_gpio_isr,
353 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
354 "main full", &collie_bat_main);
355 if (!ret) {
356 schedule_work(&bat_work);
357 return 0;
358 }
359 power_supply_unregister(&collie_bat_bu.psy);
360err_psy_reg_bu:
361 power_supply_unregister(&collie_bat_main.psy);
362err_psy_reg_main:
363
364 /* see comment in collie_bat_remove */
365 flush_scheduled_work();
366
367 i--;
368err_gpio:
369 for (; i >= 0; i--)
370 gpio_free(gpios[i].gpio);
371
372 return ret;
373}
374
375static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
376{
377 int i;
378
379 free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
380
381 power_supply_unregister(&collie_bat_bu.psy);
382 power_supply_unregister(&collie_bat_main.psy);
383
384 /*
385 * now flush all pending work.
386 * we won't get any more schedules, since all
387 * sources (isr and external_power_changed)
388 * are unregistered now.
389 */
390 flush_scheduled_work();
391
392 for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
393 gpio_free(gpios[i].gpio);
394}
395
396static struct ucb1x00_driver collie_bat_driver = {
397 .add = collie_bat_probe,
398 .remove = __devexit_p(collie_bat_remove),
399 .suspend = collie_bat_suspend,
400 .resume = collie_bat_resume,
401};
402
403static int __init collie_bat_init(void)
404{
405 return ucb1x00_register_driver(&collie_bat_driver);
406}
407
408static void __exit collie_bat_exit(void)
409{
410 ucb1x00_unregister_driver(&collie_bat_driver);
411}
412
413module_init(collie_bat_init);
414module_exit(collie_bat_exit);
415
416MODULE_LICENSE("GPL");
417MODULE_AUTHOR("Thomas Kunze");
418MODULE_DESCRIPTION("Collie battery driver");