diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
commit | 7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch) | |
tree | e730a4565e0318140d2fbd2f0415d18a339d7336 /drivers/mfd | |
parent | 41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff) | |
parent | 0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff) |
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 107 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 14 | ||||
-rw-r--r-- | drivers/mfd/asic3.c | 413 | ||||
-rw-r--r-- | drivers/mfd/da903x.c | 563 | ||||
-rw-r--r-- | drivers/mfd/htc-egpio.c | 6 | ||||
-rw-r--r-- | drivers/mfd/htc-pasic3.c | 2 | ||||
-rw-r--r-- | drivers/mfd/mcp-sa11x0.c | 8 | ||||
-rw-r--r-- | drivers/mfd/mfd-core.c | 119 | ||||
-rw-r--r-- | drivers/mfd/sm501.c | 470 | ||||
-rw-r--r-- | drivers/mfd/t7l66xb.c | 443 | ||||
-rw-r--r-- | drivers/mfd/tc6387xb.c | 192 | ||||
-rw-r--r-- | drivers/mfd/tc6393xb.c | 833 | ||||
-rw-r--r-- | drivers/mfd/twl4030-core.c | 806 | ||||
-rw-r--r-- | drivers/mfd/twl4030-irq.c | 743 | ||||
-rw-r--r-- | drivers/mfd/ucb1400_core.c | 106 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-core.c | 2 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-ts.c | 2 | ||||
-rw-r--r-- | drivers/mfd/wm8350-core.c | 1276 | ||||
-rw-r--r-- | drivers/mfd/wm8350-gpio.c | 222 | ||||
-rw-r--r-- | drivers/mfd/wm8350-i2c.c | 120 | ||||
-rw-r--r-- | drivers/mfd/wm8350-regmap.c | 1347 | ||||
-rw-r--r-- | drivers/mfd/wm8400-core.c | 455 |
22 files changed, 7994 insertions, 255 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ae96bd6242f2..5a79d2d4cdae 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -5,6 +5,10 @@ | |||
5 | menu "Multifunction device drivers" | 5 | menu "Multifunction device drivers" |
6 | depends on HAS_IOMEM | 6 | depends on HAS_IOMEM |
7 | 7 | ||
8 | config MFD_CORE | ||
9 | tristate | ||
10 | default n | ||
11 | |||
8 | config MFD_SM501 | 12 | config MFD_SM501 |
9 | tristate "Support for Silicon Motion SM501" | 13 | tristate "Support for Silicon Motion SM501" |
10 | ---help--- | 14 | ---help--- |
@@ -15,16 +19,24 @@ config MFD_SM501 | |||
15 | interface. The device may be connected by PCI or local bus with | 19 | interface. The device may be connected by PCI or local bus with |
16 | varying functions enabled. | 20 | varying functions enabled. |
17 | 21 | ||
22 | config MFD_SM501_GPIO | ||
23 | bool "Export GPIO via GPIO layer" | ||
24 | depends on MFD_SM501 && GPIOLIB | ||
25 | ---help--- | ||
26 | This option uses the gpio library layer to export the 64 GPIO | ||
27 | lines on the SM501. The platform data is used to supply the | ||
28 | base number for the first GPIO line to register. | ||
29 | |||
18 | config MFD_ASIC3 | 30 | config MFD_ASIC3 |
19 | bool "Support for Compaq ASIC3" | 31 | bool "Support for Compaq ASIC3" |
20 | depends on GENERIC_HARDIRQS && ARM | 32 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM |
21 | ---help--- | 33 | ---help--- |
22 | This driver supports the ASIC3 multifunction chip found on many | 34 | This driver supports the ASIC3 multifunction chip found on many |
23 | PDAs (mainly iPAQ and HTC based ones) | 35 | PDAs (mainly iPAQ and HTC based ones) |
24 | 36 | ||
25 | config HTC_EGPIO | 37 | config HTC_EGPIO |
26 | bool "HTC EGPIO support" | 38 | bool "HTC EGPIO support" |
27 | depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM | 39 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM |
28 | help | 40 | help |
29 | This driver supports the CPLD egpio chip present on | 41 | This driver supports the CPLD egpio chip present on |
30 | several HTC phones. It provides basic support for input | 42 | several HTC phones. It provides basic support for input |
@@ -38,6 +50,97 @@ config HTC_PASIC3 | |||
38 | HTC Magician devices, respectively. Actual functionality is | 50 | HTC Magician devices, respectively. Actual functionality is |
39 | handled by the leds-pasic3 and ds1wm drivers. | 51 | handled by the leds-pasic3 and ds1wm drivers. |
40 | 52 | ||
53 | config UCB1400_CORE | ||
54 | tristate "Philips UCB1400 Core driver" | ||
55 | depends on AC97_BUS | ||
56 | depends on GPIOLIB | ||
57 | help | ||
58 | This enables support for the Philips UCB1400 core functions. | ||
59 | The UCB1400 is an AC97 audio codec. | ||
60 | |||
61 | To compile this driver as a module, choose M here: the | ||
62 | module will be called ucb1400_core. | ||
63 | |||
64 | config TWL4030_CORE | ||
65 | bool "Texas Instruments TWL4030/TPS659x0 Support" | ||
66 | depends on I2C=y && GENERIC_HARDIRQS && (ARCH_OMAP2 || ARCH_OMAP3) | ||
67 | help | ||
68 | Say yes here if you have TWL4030 family chip on your board. | ||
69 | This core driver provides register access and IRQ handling | ||
70 | facilities, and registers devices for the various functions | ||
71 | so that function-specific drivers can bind to them. | ||
72 | |||
73 | These multi-function chips are found on many OMAP2 and OMAP3 | ||
74 | boards, providing power management, RTC, GPIO, keypad, a | ||
75 | high speed USB OTG transceiver, an audio codec (on most | ||
76 | versions) and many other features. | ||
77 | |||
78 | config MFD_TMIO | ||
79 | bool | ||
80 | default n | ||
81 | |||
82 | config MFD_T7L66XB | ||
83 | bool "Support Toshiba T7L66XB" | ||
84 | depends on ARM | ||
85 | select MFD_CORE | ||
86 | select MFD_TMIO | ||
87 | help | ||
88 | Support for Toshiba Mobile IO Controller T7L66XB | ||
89 | |||
90 | config MFD_TC6387XB | ||
91 | bool "Support Toshiba TC6387XB" | ||
92 | depends on ARM | ||
93 | select MFD_CORE | ||
94 | select MFD_TMIO | ||
95 | help | ||
96 | Support for Toshiba Mobile IO Controller TC6387XB | ||
97 | |||
98 | config MFD_TC6393XB | ||
99 | bool "Support Toshiba TC6393XB" | ||
100 | depends on GPIOLIB && ARM | ||
101 | select MFD_CORE | ||
102 | select MFD_TMIO | ||
103 | help | ||
104 | Support for Toshiba Mobile IO Controller TC6393XB | ||
105 | |||
106 | config MFD_WM8400 | ||
107 | tristate "Support Wolfson Microelectronics WM8400" | ||
108 | help | ||
109 | Support for the Wolfson Microelecronics WM8400 PMIC and audio | ||
110 | CODEC. This driver adds provides common support for accessing | ||
111 | the device, additional drivers must be enabled in order to use | ||
112 | the functionality of the device. | ||
113 | |||
114 | config MFD_WM8350 | ||
115 | tristate | ||
116 | |||
117 | config MFD_WM8350_CONFIG_MODE_0 | ||
118 | bool | ||
119 | depends on MFD_WM8350 | ||
120 | |||
121 | config MFD_WM8350_CONFIG_MODE_1 | ||
122 | bool | ||
123 | depends on MFD_WM8350 | ||
124 | |||
125 | config MFD_WM8350_CONFIG_MODE_2 | ||
126 | bool | ||
127 | depends on MFD_WM8350 | ||
128 | |||
129 | config MFD_WM8350_CONFIG_MODE_3 | ||
130 | bool | ||
131 | depends on MFD_WM8350 | ||
132 | |||
133 | config MFD_WM8350_I2C | ||
134 | tristate "Support Wolfson Microelectronics WM8350 with I2C" | ||
135 | select MFD_WM8350 | ||
136 | depends on I2C | ||
137 | help | ||
138 | The WM8350 is an integrated audio and power management | ||
139 | subsystem with watchdog and RTC functionality for embedded | ||
140 | systems. This option enables core support for the WM8350 with | ||
141 | I2C as the control interface. Additional options must be | ||
142 | selected to enable support for the functionality of the chip. | ||
143 | |||
41 | endmenu | 144 | endmenu |
42 | 145 | ||
43 | menu "Multimedia Capabilities Port drivers" | 146 | menu "Multimedia Capabilities Port drivers" |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index eef4e26807df..0acefe8aff87 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -8,6 +8,19 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o | |||
8 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 8 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
9 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o | 9 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o |
10 | 10 | ||
11 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o | ||
12 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o | ||
13 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o | ||
14 | |||
15 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | ||
16 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o | ||
17 | obj-$(CONFIG_MFD_WM8350) += wm8350.o | ||
18 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o | ||
19 | |||
20 | obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o | ||
21 | |||
22 | obj-$(CONFIG_MFD_CORE) += mfd-core.o | ||
23 | |||
11 | obj-$(CONFIG_MCP) += mcp-core.o | 24 | obj-$(CONFIG_MCP) += mcp-core.o |
12 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o | 25 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o |
13 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o | 26 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o |
@@ -16,3 +29,4 @@ obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o | |||
16 | ifeq ($(CONFIG_SA1100_ASSABET),y) | 29 | ifeq ($(CONFIG_SA1100_ASSABET),y) |
17 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o | 30 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o |
18 | endif | 31 | endif |
32 | obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | ||
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index ef8a492766a7..e4c0db4dc7b1 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
@@ -9,22 +9,35 @@ | |||
9 | * | 9 | * |
10 | * Copyright 2001 Compaq Computer Corporation. | 10 | * Copyright 2001 Compaq Computer Corporation. |
11 | * Copyright 2004-2005 Phil Blundell | 11 | * Copyright 2004-2005 Phil Blundell |
12 | * Copyright 2007 OpenedHand Ltd. | 12 | * Copyright 2007-2008 OpenedHand Ltd. |
13 | * | 13 | * |
14 | * Authors: Phil Blundell <pb@handhelds.org>, | 14 | * Authors: Phil Blundell <pb@handhelds.org>, |
15 | * Samuel Ortiz <sameo@openedhand.com> | 15 | * Samuel Ortiz <sameo@openedhand.com> |
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/version.h> | ||
20 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
21 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/gpio.h> | ||
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | 25 | ||
26 | #include <linux/mfd/asic3.h> | 26 | #include <linux/mfd/asic3.h> |
27 | 27 | ||
28 | struct asic3 { | ||
29 | void __iomem *mapping; | ||
30 | unsigned int bus_shift; | ||
31 | unsigned int irq_nr; | ||
32 | unsigned int irq_base; | ||
33 | spinlock_t lock; | ||
34 | u16 irq_bothedge[4]; | ||
35 | struct gpio_chip gpio; | ||
36 | struct device *dev; | ||
37 | }; | ||
38 | |||
39 | static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); | ||
40 | |||
28 | static inline void asic3_write_register(struct asic3 *asic, | 41 | static inline void asic3_write_register(struct asic3 *asic, |
29 | unsigned int reg, u32 value) | 42 | unsigned int reg, u32 value) |
30 | { | 43 | { |
@@ -41,8 +54,8 @@ static inline u32 asic3_read_register(struct asic3 *asic, | |||
41 | 54 | ||
42 | /* IRQs */ | 55 | /* IRQs */ |
43 | #define MAX_ASIC_ISR_LOOPS 20 | 56 | #define MAX_ASIC_ISR_LOOPS 20 |
44 | #define ASIC3_GPIO_Base_INCR \ | 57 | #define ASIC3_GPIO_BASE_INCR \ |
45 | (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base) | 58 | (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE) |
46 | 59 | ||
47 | static void asic3_irq_flip_edge(struct asic3 *asic, | 60 | static void asic3_irq_flip_edge(struct asic3 *asic, |
48 | u32 base, int bit) | 61 | u32 base, int bit) |
@@ -52,10 +65,10 @@ static void asic3_irq_flip_edge(struct asic3 *asic, | |||
52 | 65 | ||
53 | spin_lock_irqsave(&asic->lock, flags); | 66 | spin_lock_irqsave(&asic->lock, flags); |
54 | edge = asic3_read_register(asic, | 67 | edge = asic3_read_register(asic, |
55 | base + ASIC3_GPIO_EdgeTrigger); | 68 | base + ASIC3_GPIO_EDGE_TRIGGER); |
56 | edge ^= bit; | 69 | edge ^= bit; |
57 | asic3_write_register(asic, | 70 | asic3_write_register(asic, |
58 | base + ASIC3_GPIO_EdgeTrigger, edge); | 71 | base + ASIC3_GPIO_EDGE_TRIGGER, edge); |
59 | spin_unlock_irqrestore(&asic->lock, flags); | 72 | spin_unlock_irqrestore(&asic->lock, flags); |
60 | } | 73 | } |
61 | 74 | ||
@@ -75,7 +88,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
75 | 88 | ||
76 | spin_lock_irqsave(&asic->lock, flags); | 89 | spin_lock_irqsave(&asic->lock, flags); |
77 | status = asic3_read_register(asic, | 90 | status = asic3_read_register(asic, |
78 | ASIC3_OFFSET(INTR, PIntStat)); | 91 | ASIC3_OFFSET(INTR, P_INT_STAT)); |
79 | spin_unlock_irqrestore(&asic->lock, flags); | 92 | spin_unlock_irqrestore(&asic->lock, flags); |
80 | 93 | ||
81 | /* Check all ten register bits */ | 94 | /* Check all ten register bits */ |
@@ -87,17 +100,17 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
87 | if (status & (1 << bank)) { | 100 | if (status & (1 << bank)) { |
88 | unsigned long base, istat; | 101 | unsigned long base, istat; |
89 | 102 | ||
90 | base = ASIC3_GPIO_A_Base | 103 | base = ASIC3_GPIO_A_BASE |
91 | + bank * ASIC3_GPIO_Base_INCR; | 104 | + bank * ASIC3_GPIO_BASE_INCR; |
92 | 105 | ||
93 | spin_lock_irqsave(&asic->lock, flags); | 106 | spin_lock_irqsave(&asic->lock, flags); |
94 | istat = asic3_read_register(asic, | 107 | istat = asic3_read_register(asic, |
95 | base + | 108 | base + |
96 | ASIC3_GPIO_IntStatus); | 109 | ASIC3_GPIO_INT_STATUS); |
97 | /* Clearing IntStatus */ | 110 | /* Clearing IntStatus */ |
98 | asic3_write_register(asic, | 111 | asic3_write_register(asic, |
99 | base + | 112 | base + |
100 | ASIC3_GPIO_IntStatus, 0); | 113 | ASIC3_GPIO_INT_STATUS, 0); |
101 | spin_unlock_irqrestore(&asic->lock, flags); | 114 | spin_unlock_irqrestore(&asic->lock, flags); |
102 | 115 | ||
103 | for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) { | 116 | for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) { |
@@ -110,7 +123,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
110 | irqnr = asic->irq_base + | 123 | irqnr = asic->irq_base + |
111 | (ASIC3_GPIOS_PER_BANK * bank) | 124 | (ASIC3_GPIOS_PER_BANK * bank) |
112 | + i; | 125 | + i; |
113 | desc = irq_desc + irqnr; | 126 | desc = irq_to_desc(irqnr); |
114 | desc->handle_irq(irqnr, desc); | 127 | desc->handle_irq(irqnr, desc); |
115 | if (asic->irq_bothedge[bank] & bit) | 128 | if (asic->irq_bothedge[bank] & bit) |
116 | asic3_irq_flip_edge(asic, base, | 129 | asic3_irq_flip_edge(asic, base, |
@@ -123,7 +136,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
123 | for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { | 136 | for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { |
124 | /* They start at bit 4 and go up */ | 137 | /* They start at bit 4 and go up */ |
125 | if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) { | 138 | if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) { |
126 | desc = irq_desc + + i; | 139 | desc = irq_to_desc(asic->irq_base + i); |
127 | desc->handle_irq(asic->irq_base + i, | 140 | desc->handle_irq(asic->irq_base + i, |
128 | desc); | 141 | desc); |
129 | } | 142 | } |
@@ -131,8 +144,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
131 | } | 144 | } |
132 | 145 | ||
133 | if (iter >= MAX_ASIC_ISR_LOOPS) | 146 | if (iter >= MAX_ASIC_ISR_LOOPS) |
134 | printk(KERN_ERR "%s: interrupt processing overrun\n", | 147 | dev_err(asic->dev, "interrupt processing overrun\n"); |
135 | __func__); | ||
136 | } | 148 | } |
137 | 149 | ||
138 | static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) | 150 | static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) |
@@ -141,7 +153,7 @@ static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) | |||
141 | 153 | ||
142 | n = (irq - asic->irq_base) >> 4; | 154 | n = (irq - asic->irq_base) >> 4; |
143 | 155 | ||
144 | return (n * (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base)); | 156 | return (n * (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE)); |
145 | } | 157 | } |
146 | 158 | ||
147 | static inline int asic3_irq_to_index(struct asic3 *asic, int irq) | 159 | static inline int asic3_irq_to_index(struct asic3 *asic, int irq) |
@@ -159,9 +171,9 @@ static void asic3_mask_gpio_irq(unsigned int irq) | |||
159 | index = asic3_irq_to_index(asic, irq); | 171 | index = asic3_irq_to_index(asic, irq); |
160 | 172 | ||
161 | spin_lock_irqsave(&asic->lock, flags); | 173 | spin_lock_irqsave(&asic->lock, flags); |
162 | val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask); | 174 | val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); |
163 | val |= 1 << index; | 175 | val |= 1 << index; |
164 | asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val); | 176 | asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); |
165 | spin_unlock_irqrestore(&asic->lock, flags); | 177 | spin_unlock_irqrestore(&asic->lock, flags); |
166 | } | 178 | } |
167 | 179 | ||
@@ -173,15 +185,15 @@ static void asic3_mask_irq(unsigned int irq) | |||
173 | 185 | ||
174 | spin_lock_irqsave(&asic->lock, flags); | 186 | spin_lock_irqsave(&asic->lock, flags); |
175 | regval = asic3_read_register(asic, | 187 | regval = asic3_read_register(asic, |
176 | ASIC3_INTR_Base + | 188 | ASIC3_INTR_BASE + |
177 | ASIC3_INTR_IntMask); | 189 | ASIC3_INTR_INT_MASK); |
178 | 190 | ||
179 | regval &= ~(ASIC3_INTMASK_MASK0 << | 191 | regval &= ~(ASIC3_INTMASK_MASK0 << |
180 | (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); | 192 | (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); |
181 | 193 | ||
182 | asic3_write_register(asic, | 194 | asic3_write_register(asic, |
183 | ASIC3_INTR_Base + | 195 | ASIC3_INTR_BASE + |
184 | ASIC3_INTR_IntMask, | 196 | ASIC3_INTR_INT_MASK, |
185 | regval); | 197 | regval); |
186 | spin_unlock_irqrestore(&asic->lock, flags); | 198 | spin_unlock_irqrestore(&asic->lock, flags); |
187 | } | 199 | } |
@@ -196,9 +208,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq) | |||
196 | index = asic3_irq_to_index(asic, irq); | 208 | index = asic3_irq_to_index(asic, irq); |
197 | 209 | ||
198 | spin_lock_irqsave(&asic->lock, flags); | 210 | spin_lock_irqsave(&asic->lock, flags); |
199 | val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask); | 211 | val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); |
200 | val &= ~(1 << index); | 212 | val &= ~(1 << index); |
201 | asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val); | 213 | asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); |
202 | spin_unlock_irqrestore(&asic->lock, flags); | 214 | spin_unlock_irqrestore(&asic->lock, flags); |
203 | } | 215 | } |
204 | 216 | ||
@@ -210,15 +222,15 @@ static void asic3_unmask_irq(unsigned int irq) | |||
210 | 222 | ||
211 | spin_lock_irqsave(&asic->lock, flags); | 223 | spin_lock_irqsave(&asic->lock, flags); |
212 | regval = asic3_read_register(asic, | 224 | regval = asic3_read_register(asic, |
213 | ASIC3_INTR_Base + | 225 | ASIC3_INTR_BASE + |
214 | ASIC3_INTR_IntMask); | 226 | ASIC3_INTR_INT_MASK); |
215 | 227 | ||
216 | regval |= (ASIC3_INTMASK_MASK0 << | 228 | regval |= (ASIC3_INTMASK_MASK0 << |
217 | (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); | 229 | (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); |
218 | 230 | ||
219 | asic3_write_register(asic, | 231 | asic3_write_register(asic, |
220 | ASIC3_INTR_Base + | 232 | ASIC3_INTR_BASE + |
221 | ASIC3_INTR_IntMask, | 233 | ASIC3_INTR_INT_MASK, |
222 | regval); | 234 | regval); |
223 | spin_unlock_irqrestore(&asic->lock, flags); | 235 | spin_unlock_irqrestore(&asic->lock, flags); |
224 | } | 236 | } |
@@ -236,45 +248,45 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) | |||
236 | 248 | ||
237 | spin_lock_irqsave(&asic->lock, flags); | 249 | spin_lock_irqsave(&asic->lock, flags); |
238 | level = asic3_read_register(asic, | 250 | level = asic3_read_register(asic, |
239 | bank + ASIC3_GPIO_LevelTrigger); | 251 | bank + ASIC3_GPIO_LEVEL_TRIGGER); |
240 | edge = asic3_read_register(asic, | 252 | edge = asic3_read_register(asic, |
241 | bank + ASIC3_GPIO_EdgeTrigger); | 253 | bank + ASIC3_GPIO_EDGE_TRIGGER); |
242 | trigger = asic3_read_register(asic, | 254 | trigger = asic3_read_register(asic, |
243 | bank + ASIC3_GPIO_TriggerType); | 255 | bank + ASIC3_GPIO_TRIGGER_TYPE); |
244 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit; | 256 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit; |
245 | 257 | ||
246 | if (type == IRQT_RISING) { | 258 | if (type == IRQ_TYPE_EDGE_RISING) { |
247 | trigger |= bit; | 259 | trigger |= bit; |
248 | edge |= bit; | 260 | edge |= bit; |
249 | } else if (type == IRQT_FALLING) { | 261 | } else if (type == IRQ_TYPE_EDGE_FALLING) { |
250 | trigger |= bit; | 262 | trigger |= bit; |
251 | edge &= ~bit; | 263 | edge &= ~bit; |
252 | } else if (type == IRQT_BOTHEDGE) { | 264 | } else if (type == IRQ_TYPE_EDGE_BOTH) { |
253 | trigger |= bit; | 265 | trigger |= bit; |
254 | if (asic3_gpio_get_value(asic, irq - asic->irq_base)) | 266 | if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base)) |
255 | edge &= ~bit; | 267 | edge &= ~bit; |
256 | else | 268 | else |
257 | edge |= bit; | 269 | edge |= bit; |
258 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit; | 270 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit; |
259 | } else if (type == IRQT_LOW) { | 271 | } else if (type == IRQ_TYPE_LEVEL_LOW) { |
260 | trigger &= ~bit; | 272 | trigger &= ~bit; |
261 | level &= ~bit; | 273 | level &= ~bit; |
262 | } else if (type == IRQT_HIGH) { | 274 | } else if (type == IRQ_TYPE_LEVEL_HIGH) { |
263 | trigger &= ~bit; | 275 | trigger &= ~bit; |
264 | level |= bit; | 276 | level |= bit; |
265 | } else { | 277 | } else { |
266 | /* | 278 | /* |
267 | * if type == IRQT_NOEDGE, we should mask interrupts, but | 279 | * if type == IRQ_TYPE_NONE, we should mask interrupts, but |
268 | * be careful to not unmask them if mask was also called. | 280 | * be careful to not unmask them if mask was also called. |
269 | * Probably need internal state for mask. | 281 | * Probably need internal state for mask. |
270 | */ | 282 | */ |
271 | printk(KERN_NOTICE "asic3: irq type not changed.\n"); | 283 | dev_notice(asic->dev, "irq type not changed\n"); |
272 | } | 284 | } |
273 | asic3_write_register(asic, bank + ASIC3_GPIO_LevelTrigger, | 285 | asic3_write_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER, |
274 | level); | 286 | level); |
275 | asic3_write_register(asic, bank + ASIC3_GPIO_EdgeTrigger, | 287 | asic3_write_register(asic, bank + ASIC3_GPIO_EDGE_TRIGGER, |
276 | edge); | 288 | edge); |
277 | asic3_write_register(asic, bank + ASIC3_GPIO_TriggerType, | 289 | asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE, |
278 | trigger); | 290 | trigger); |
279 | spin_unlock_irqrestore(&asic->lock, flags); | 291 | spin_unlock_irqrestore(&asic->lock, flags); |
280 | return 0; | 292 | return 0; |
@@ -295,15 +307,17 @@ static struct irq_chip asic3_irq_chip = { | |||
295 | .unmask = asic3_unmask_irq, | 307 | .unmask = asic3_unmask_irq, |
296 | }; | 308 | }; |
297 | 309 | ||
298 | static int asic3_irq_probe(struct platform_device *pdev) | 310 | static int __init asic3_irq_probe(struct platform_device *pdev) |
299 | { | 311 | { |
300 | struct asic3 *asic = platform_get_drvdata(pdev); | 312 | struct asic3 *asic = platform_get_drvdata(pdev); |
301 | unsigned long clksel = 0; | 313 | unsigned long clksel = 0; |
302 | unsigned int irq, irq_base; | 314 | unsigned int irq, irq_base; |
315 | int ret; | ||
303 | 316 | ||
304 | asic->irq_nr = platform_get_irq(pdev, 0); | 317 | ret = platform_get_irq(pdev, 0); |
305 | if (asic->irq_nr < 0) | 318 | if (ret < 0) |
306 | return asic->irq_nr; | 319 | return ret; |
320 | asic->irq_nr = ret; | ||
307 | 321 | ||
308 | /* turn on clock to IRQ controller */ | 322 | /* turn on clock to IRQ controller */ |
309 | clksel |= CLOCK_SEL_CX; | 323 | clksel |= CLOCK_SEL_CX; |
@@ -323,11 +337,11 @@ static int asic3_irq_probe(struct platform_device *pdev) | |||
323 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 337 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
324 | } | 338 | } |
325 | 339 | ||
326 | asic3_write_register(asic, ASIC3_OFFSET(INTR, IntMask), | 340 | asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), |
327 | ASIC3_INTMASK_GINTMASK); | 341 | ASIC3_INTMASK_GINTMASK); |
328 | 342 | ||
329 | set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); | 343 | set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); |
330 | set_irq_type(asic->irq_nr, IRQT_RISING); | 344 | set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); |
331 | set_irq_data(asic->irq_nr, asic); | 345 | set_irq_data(asic->irq_nr, asic); |
332 | 346 | ||
333 | return 0; | 347 | return 0; |
@@ -350,149 +364,183 @@ static void asic3_irq_remove(struct platform_device *pdev) | |||
350 | } | 364 | } |
351 | 365 | ||
352 | /* GPIOs */ | 366 | /* GPIOs */ |
353 | static inline u32 asic3_get_gpio(struct asic3 *asic, unsigned int base, | 367 | static int asic3_gpio_direction(struct gpio_chip *chip, |
354 | unsigned int function) | 368 | unsigned offset, int out) |
355 | { | ||
356 | return asic3_read_register(asic, base + function); | ||
357 | } | ||
358 | |||
359 | static void asic3_set_gpio(struct asic3 *asic, unsigned int base, | ||
360 | unsigned int function, u32 bits, u32 val) | ||
361 | { | 369 | { |
370 | u32 mask = ASIC3_GPIO_TO_MASK(offset), out_reg; | ||
371 | unsigned int gpio_base; | ||
362 | unsigned long flags; | 372 | unsigned long flags; |
373 | struct asic3 *asic; | ||
374 | |||
375 | asic = container_of(chip, struct asic3, gpio); | ||
376 | gpio_base = ASIC3_GPIO_TO_BASE(offset); | ||
377 | |||
378 | if (gpio_base > ASIC3_GPIO_D_BASE) { | ||
379 | dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", | ||
380 | gpio_base, offset); | ||
381 | return -EINVAL; | ||
382 | } | ||
363 | 383 | ||
364 | spin_lock_irqsave(&asic->lock, flags); | 384 | spin_lock_irqsave(&asic->lock, flags); |
365 | val |= (asic3_read_register(asic, base + function) & ~bits); | ||
366 | 385 | ||
367 | asic3_write_register(asic, base + function, val); | 386 | out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION); |
387 | |||
388 | /* Input is 0, Output is 1 */ | ||
389 | if (out) | ||
390 | out_reg |= mask; | ||
391 | else | ||
392 | out_reg &= ~mask; | ||
393 | |||
394 | asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg); | ||
395 | |||
368 | spin_unlock_irqrestore(&asic->lock, flags); | 396 | spin_unlock_irqrestore(&asic->lock, flags); |
397 | |||
398 | return 0; | ||
399 | |||
400 | } | ||
401 | |||
402 | static int asic3_gpio_direction_input(struct gpio_chip *chip, | ||
403 | unsigned offset) | ||
404 | { | ||
405 | return asic3_gpio_direction(chip, offset, 0); | ||
406 | } | ||
407 | |||
408 | static int asic3_gpio_direction_output(struct gpio_chip *chip, | ||
409 | unsigned offset, int value) | ||
410 | { | ||
411 | return asic3_gpio_direction(chip, offset, 1); | ||
369 | } | 412 | } |
370 | 413 | ||
371 | #define asic3_get_gpio_a(asic, fn) \ | 414 | static int asic3_gpio_get(struct gpio_chip *chip, |
372 | asic3_get_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn) | 415 | unsigned offset) |
373 | #define asic3_get_gpio_b(asic, fn) \ | ||
374 | asic3_get_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn) | ||
375 | #define asic3_get_gpio_c(asic, fn) \ | ||
376 | asic3_get_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn) | ||
377 | #define asic3_get_gpio_d(asic, fn) \ | ||
378 | asic3_get_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn) | ||
379 | |||
380 | #define asic3_set_gpio_a(asic, fn, bits, val) \ | ||
381 | asic3_set_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn, bits, val) | ||
382 | #define asic3_set_gpio_b(asic, fn, bits, val) \ | ||
383 | asic3_set_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn, bits, val) | ||
384 | #define asic3_set_gpio_c(asic, fn, bits, val) \ | ||
385 | asic3_set_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn, bits, val) | ||
386 | #define asic3_set_gpio_d(asic, fn, bits, val) \ | ||
387 | asic3_set_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn, bits, val) | ||
388 | |||
389 | #define asic3_set_gpio_banks(asic, fn, bits, pdata, field) \ | ||
390 | do { \ | ||
391 | asic3_set_gpio_a((asic), fn, (bits), (pdata)->gpio_a.field); \ | ||
392 | asic3_set_gpio_b((asic), fn, (bits), (pdata)->gpio_b.field); \ | ||
393 | asic3_set_gpio_c((asic), fn, (bits), (pdata)->gpio_c.field); \ | ||
394 | asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \ | ||
395 | } while (0) | ||
396 | |||
397 | int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio) | ||
398 | { | 416 | { |
399 | u32 mask = ASIC3_GPIO_bit(gpio); | 417 | unsigned int gpio_base; |
400 | 418 | u32 mask = ASIC3_GPIO_TO_MASK(offset); | |
401 | switch (gpio >> 4) { | 419 | struct asic3 *asic; |
402 | case ASIC3_GPIO_BANK_A: | 420 | |
403 | return asic3_get_gpio_a(asic, Status) & mask; | 421 | asic = container_of(chip, struct asic3, gpio); |
404 | case ASIC3_GPIO_BANK_B: | 422 | gpio_base = ASIC3_GPIO_TO_BASE(offset); |
405 | return asic3_get_gpio_b(asic, Status) & mask; | 423 | |
406 | case ASIC3_GPIO_BANK_C: | 424 | if (gpio_base > ASIC3_GPIO_D_BASE) { |
407 | return asic3_get_gpio_c(asic, Status) & mask; | 425 | dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", |
408 | case ASIC3_GPIO_BANK_D: | 426 | gpio_base, offset); |
409 | return asic3_get_gpio_d(asic, Status) & mask; | ||
410 | default: | ||
411 | printk(KERN_ERR "%s: invalid GPIO value 0x%x", | ||
412 | __func__, gpio); | ||
413 | return -EINVAL; | 427 | return -EINVAL; |
414 | } | 428 | } |
429 | |||
430 | return asic3_read_register(asic, gpio_base + ASIC3_GPIO_STATUS) & mask; | ||
415 | } | 431 | } |
416 | EXPORT_SYMBOL(asic3_gpio_get_value); | ||
417 | 432 | ||
418 | void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val) | 433 | static void asic3_gpio_set(struct gpio_chip *chip, |
434 | unsigned offset, int value) | ||
419 | { | 435 | { |
420 | u32 mask = ASIC3_GPIO_bit(gpio); | 436 | u32 mask, out_reg; |
421 | u32 bitval = 0; | 437 | unsigned int gpio_base; |
422 | if (val) | 438 | unsigned long flags; |
423 | bitval = mask; | 439 | struct asic3 *asic; |
424 | 440 | ||
425 | switch (gpio >> 4) { | 441 | asic = container_of(chip, struct asic3, gpio); |
426 | case ASIC3_GPIO_BANK_A: | 442 | gpio_base = ASIC3_GPIO_TO_BASE(offset); |
427 | asic3_set_gpio_a(asic, Out, mask, bitval); | 443 | |
428 | return; | 444 | if (gpio_base > ASIC3_GPIO_D_BASE) { |
429 | case ASIC3_GPIO_BANK_B: | 445 | dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", |
430 | asic3_set_gpio_b(asic, Out, mask, bitval); | 446 | gpio_base, offset); |
431 | return; | ||
432 | case ASIC3_GPIO_BANK_C: | ||
433 | asic3_set_gpio_c(asic, Out, mask, bitval); | ||
434 | return; | ||
435 | case ASIC3_GPIO_BANK_D: | ||
436 | asic3_set_gpio_d(asic, Out, mask, bitval); | ||
437 | return; | ||
438 | default: | ||
439 | printk(KERN_ERR "%s: invalid GPIO value 0x%x", | ||
440 | __func__, gpio); | ||
441 | return; | 447 | return; |
442 | } | 448 | } |
449 | |||
450 | mask = ASIC3_GPIO_TO_MASK(offset); | ||
451 | |||
452 | spin_lock_irqsave(&asic->lock, flags); | ||
453 | |||
454 | out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT); | ||
455 | |||
456 | if (value) | ||
457 | out_reg |= mask; | ||
458 | else | ||
459 | out_reg &= ~mask; | ||
460 | |||
461 | asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg); | ||
462 | |||
463 | spin_unlock_irqrestore(&asic->lock, flags); | ||
464 | |||
465 | return; | ||
443 | } | 466 | } |
444 | EXPORT_SYMBOL(asic3_gpio_set_value); | ||
445 | 467 | ||
446 | static int asic3_gpio_probe(struct platform_device *pdev) | 468 | static __init int asic3_gpio_probe(struct platform_device *pdev, |
469 | u16 *gpio_config, int num) | ||
447 | { | 470 | { |
448 | struct asic3_platform_data *pdata = pdev->dev.platform_data; | ||
449 | struct asic3 *asic = platform_get_drvdata(pdev); | 471 | struct asic3 *asic = platform_get_drvdata(pdev); |
472 | u16 alt_reg[ASIC3_NUM_GPIO_BANKS]; | ||
473 | u16 out_reg[ASIC3_NUM_GPIO_BANKS]; | ||
474 | u16 dir_reg[ASIC3_NUM_GPIO_BANKS]; | ||
475 | int i; | ||
476 | |||
477 | memzero(alt_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); | ||
478 | memzero(out_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); | ||
479 | memzero(dir_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); | ||
480 | |||
481 | /* Enable all GPIOs */ | ||
482 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, MASK), 0xffff); | ||
483 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, MASK), 0xffff); | ||
484 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, MASK), 0xffff); | ||
485 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, MASK), 0xffff); | ||
486 | |||
487 | for (i = 0; i < num; i++) { | ||
488 | u8 alt, pin, dir, init, bank_num, bit_num; | ||
489 | u16 config = gpio_config[i]; | ||
490 | |||
491 | pin = ASIC3_CONFIG_GPIO_PIN(config); | ||
492 | alt = ASIC3_CONFIG_GPIO_ALT(config); | ||
493 | dir = ASIC3_CONFIG_GPIO_DIR(config); | ||
494 | init = ASIC3_CONFIG_GPIO_INIT(config); | ||
495 | |||
496 | bank_num = ASIC3_GPIO_TO_BANK(pin); | ||
497 | bit_num = ASIC3_GPIO_TO_BIT(pin); | ||
498 | |||
499 | alt_reg[bank_num] |= (alt << bit_num); | ||
500 | out_reg[bank_num] |= (init << bit_num); | ||
501 | dir_reg[bank_num] |= (dir << bit_num); | ||
502 | } | ||
450 | 503 | ||
451 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, Mask), 0xffff); | 504 | for (i = 0; i < ASIC3_NUM_GPIO_BANKS; i++) { |
452 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, Mask), 0xffff); | 505 | asic3_write_register(asic, |
453 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, Mask), 0xffff); | 506 | ASIC3_BANK_TO_BASE(i) + |
454 | asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, Mask), 0xffff); | 507 | ASIC3_GPIO_DIRECTION, |
455 | 508 | dir_reg[i]); | |
456 | asic3_set_gpio_a(asic, SleepMask, 0xffff, 0xffff); | 509 | asic3_write_register(asic, |
457 | asic3_set_gpio_b(asic, SleepMask, 0xffff, 0xffff); | 510 | ASIC3_BANK_TO_BASE(i) + ASIC3_GPIO_OUT, |
458 | asic3_set_gpio_c(asic, SleepMask, 0xffff, 0xffff); | 511 | out_reg[i]); |
459 | asic3_set_gpio_d(asic, SleepMask, 0xffff, 0xffff); | 512 | asic3_write_register(asic, |
460 | 513 | ASIC3_BANK_TO_BASE(i) + | |
461 | if (pdata) { | 514 | ASIC3_GPIO_ALT_FUNCTION, |
462 | asic3_set_gpio_banks(asic, Out, 0xffff, pdata, init); | 515 | alt_reg[i]); |
463 | asic3_set_gpio_banks(asic, Direction, 0xffff, pdata, dir); | ||
464 | asic3_set_gpio_banks(asic, SleepMask, 0xffff, pdata, | ||
465 | sleep_mask); | ||
466 | asic3_set_gpio_banks(asic, SleepOut, 0xffff, pdata, sleep_out); | ||
467 | asic3_set_gpio_banks(asic, BattFaultOut, 0xffff, pdata, | ||
468 | batt_fault_out); | ||
469 | asic3_set_gpio_banks(asic, SleepConf, 0xffff, pdata, | ||
470 | sleep_conf); | ||
471 | asic3_set_gpio_banks(asic, AltFunction, 0xffff, pdata, | ||
472 | alt_function); | ||
473 | } | 516 | } |
474 | 517 | ||
475 | return 0; | 518 | return gpiochip_add(&asic->gpio); |
476 | } | 519 | } |
477 | 520 | ||
478 | static void asic3_gpio_remove(struct platform_device *pdev) | 521 | static int asic3_gpio_remove(struct platform_device *pdev) |
479 | { | 522 | { |
480 | return; | 523 | struct asic3 *asic = platform_get_drvdata(pdev); |
524 | |||
525 | return gpiochip_remove(&asic->gpio); | ||
481 | } | 526 | } |
482 | 527 | ||
483 | 528 | ||
484 | /* Core */ | 529 | /* Core */ |
485 | static int asic3_probe(struct platform_device *pdev) | 530 | static int __init asic3_probe(struct platform_device *pdev) |
486 | { | 531 | { |
487 | struct asic3_platform_data *pdata = pdev->dev.platform_data; | 532 | struct asic3_platform_data *pdata = pdev->dev.platform_data; |
488 | struct asic3 *asic; | 533 | struct asic3 *asic; |
489 | struct resource *mem; | 534 | struct resource *mem; |
490 | unsigned long clksel; | 535 | unsigned long clksel; |
491 | int ret; | 536 | int map_size; |
537 | int ret = 0; | ||
492 | 538 | ||
493 | asic = kzalloc(sizeof(struct asic3), GFP_KERNEL); | 539 | asic = kzalloc(sizeof(struct asic3), GFP_KERNEL); |
494 | if (!asic) | 540 | if (asic == NULL) { |
541 | printk(KERN_ERR "kzalloc failed\n"); | ||
495 | return -ENOMEM; | 542 | return -ENOMEM; |
543 | } | ||
496 | 544 | ||
497 | spin_lock_init(&asic->lock); | 545 | spin_lock_init(&asic->lock); |
498 | platform_set_drvdata(pdev, asic); | 546 | platform_set_drvdata(pdev, asic); |
@@ -501,49 +549,58 @@ static int asic3_probe(struct platform_device *pdev) | |||
501 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 549 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
502 | if (!mem) { | 550 | if (!mem) { |
503 | ret = -ENOMEM; | 551 | ret = -ENOMEM; |
504 | printk(KERN_ERR "asic3: no MEM resource\n"); | 552 | dev_err(asic->dev, "no MEM resource\n"); |
505 | goto err_out_1; | 553 | goto out_free; |
506 | } | 554 | } |
507 | 555 | ||
508 | asic->mapping = ioremap(mem->start, PAGE_SIZE); | 556 | map_size = mem->end - mem->start + 1; |
557 | asic->mapping = ioremap(mem->start, map_size); | ||
509 | if (!asic->mapping) { | 558 | if (!asic->mapping) { |
510 | ret = -ENOMEM; | 559 | ret = -ENOMEM; |
511 | printk(KERN_ERR "asic3: couldn't ioremap\n"); | 560 | dev_err(asic->dev, "Couldn't ioremap\n"); |
512 | goto err_out_1; | 561 | goto out_free; |
513 | } | 562 | } |
514 | 563 | ||
515 | asic->irq_base = pdata->irq_base; | 564 | asic->irq_base = pdata->irq_base; |
516 | 565 | ||
517 | if (pdata && pdata->bus_shift) | 566 | /* calculate bus shift from mem resource */ |
518 | asic->bus_shift = 2 - pdata->bus_shift; | 567 | asic->bus_shift = 2 - (map_size >> 12); |
519 | else | ||
520 | asic->bus_shift = 0; | ||
521 | 568 | ||
522 | clksel = 0; | 569 | clksel = 0; |
523 | asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); | 570 | asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); |
524 | 571 | ||
525 | ret = asic3_irq_probe(pdev); | 572 | ret = asic3_irq_probe(pdev); |
526 | if (ret < 0) { | 573 | if (ret < 0) { |
527 | printk(KERN_ERR "asic3: couldn't probe IRQs\n"); | 574 | dev_err(asic->dev, "Couldn't probe IRQs\n"); |
528 | goto err_out_2; | 575 | goto out_unmap; |
529 | } | 576 | } |
530 | asic3_gpio_probe(pdev); | ||
531 | 577 | ||
532 | if (pdata->children) { | 578 | asic->gpio.base = pdata->gpio_base; |
533 | int i; | 579 | asic->gpio.ngpio = ASIC3_NUM_GPIOS; |
534 | for (i = 0; i < pdata->n_children; i++) { | 580 | asic->gpio.get = asic3_gpio_get; |
535 | pdata->children[i]->dev.parent = &pdev->dev; | 581 | asic->gpio.set = asic3_gpio_set; |
536 | platform_device_register(pdata->children[i]); | 582 | asic->gpio.direction_input = asic3_gpio_direction_input; |
537 | } | 583 | asic->gpio.direction_output = asic3_gpio_direction_output; |
584 | |||
585 | ret = asic3_gpio_probe(pdev, | ||
586 | pdata->gpio_config, | ||
587 | pdata->gpio_config_num); | ||
588 | if (ret < 0) { | ||
589 | dev_err(asic->dev, "GPIO probe failed\n"); | ||
590 | goto out_irq; | ||
538 | } | 591 | } |
539 | 592 | ||
540 | printk(KERN_INFO "ASIC3 Core driver\n"); | 593 | dev_info(asic->dev, "ASIC3 Core driver\n"); |
541 | 594 | ||
542 | return 0; | 595 | return 0; |
543 | 596 | ||
544 | err_out_2: | 597 | out_irq: |
598 | asic3_irq_remove(pdev); | ||
599 | |||
600 | out_unmap: | ||
545 | iounmap(asic->mapping); | 601 | iounmap(asic->mapping); |
546 | err_out_1: | 602 | |
603 | out_free: | ||
547 | kfree(asic); | 604 | kfree(asic); |
548 | 605 | ||
549 | return ret; | 606 | return ret; |
@@ -551,9 +608,12 @@ static int asic3_probe(struct platform_device *pdev) | |||
551 | 608 | ||
552 | static int asic3_remove(struct platform_device *pdev) | 609 | static int asic3_remove(struct platform_device *pdev) |
553 | { | 610 | { |
611 | int ret; | ||
554 | struct asic3 *asic = platform_get_drvdata(pdev); | 612 | struct asic3 *asic = platform_get_drvdata(pdev); |
555 | 613 | ||
556 | asic3_gpio_remove(pdev); | 614 | ret = asic3_gpio_remove(pdev); |
615 | if (ret < 0) | ||
616 | return ret; | ||
557 | asic3_irq_remove(pdev); | 617 | asic3_irq_remove(pdev); |
558 | 618 | ||
559 | asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); | 619 | asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); |
@@ -573,7 +633,6 @@ static struct platform_driver asic3_device_driver = { | |||
573 | .driver = { | 633 | .driver = { |
574 | .name = "asic3", | 634 | .name = "asic3", |
575 | }, | 635 | }, |
576 | .probe = asic3_probe, | ||
577 | .remove = __devexit_p(asic3_remove), | 636 | .remove = __devexit_p(asic3_remove), |
578 | .shutdown = asic3_shutdown, | 637 | .shutdown = asic3_shutdown, |
579 | }; | 638 | }; |
@@ -581,7 +640,7 @@ static struct platform_driver asic3_device_driver = { | |||
581 | static int __init asic3_init(void) | 640 | static int __init asic3_init(void) |
582 | { | 641 | { |
583 | int retval = 0; | 642 | int retval = 0; |
584 | retval = platform_driver_register(&asic3_device_driver); | 643 | retval = platform_driver_probe(&asic3_device_driver, asic3_probe); |
585 | return retval; | 644 | return retval; |
586 | } | 645 | } |
587 | 646 | ||
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c new file mode 100644 index 000000000000..b57326ae464d --- /dev/null +++ b/drivers/mfd/da903x.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | * Base driver for Dialog Semiconductor DA9030/DA9034 | ||
3 | * | ||
4 | * Copyright (C) 2008 Compulab, Ltd. | ||
5 | * Mike Rapoport <mike@compulab.co.il> | ||
6 | * | ||
7 | * Copyright (C) 2006-2008 Marvell International Ltd. | ||
8 | * Eric Miao <eric.miao@marvell.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/mfd/da903x.h> | ||
21 | |||
22 | #define DA9030_CHIP_ID 0x00 | ||
23 | #define DA9030_EVENT_A 0x01 | ||
24 | #define DA9030_EVENT_B 0x02 | ||
25 | #define DA9030_EVENT_C 0x03 | ||
26 | #define DA9030_STATUS 0x04 | ||
27 | #define DA9030_IRQ_MASK_A 0x05 | ||
28 | #define DA9030_IRQ_MASK_B 0x06 | ||
29 | #define DA9030_IRQ_MASK_C 0x07 | ||
30 | #define DA9030_SYS_CTRL_A 0x08 | ||
31 | #define DA9030_SYS_CTRL_B 0x09 | ||
32 | #define DA9030_FAULT_LOG 0x0a | ||
33 | |||
34 | #define DA9034_CHIP_ID 0x00 | ||
35 | #define DA9034_EVENT_A 0x01 | ||
36 | #define DA9034_EVENT_B 0x02 | ||
37 | #define DA9034_EVENT_C 0x03 | ||
38 | #define DA9034_EVENT_D 0x04 | ||
39 | #define DA9034_STATUS_A 0x05 | ||
40 | #define DA9034_STATUS_B 0x06 | ||
41 | #define DA9034_IRQ_MASK_A 0x07 | ||
42 | #define DA9034_IRQ_MASK_B 0x08 | ||
43 | #define DA9034_IRQ_MASK_C 0x09 | ||
44 | #define DA9034_IRQ_MASK_D 0x0a | ||
45 | #define DA9034_SYS_CTRL_A 0x0b | ||
46 | #define DA9034_SYS_CTRL_B 0x0c | ||
47 | #define DA9034_FAULT_LOG 0x0d | ||
48 | |||
49 | struct da903x_chip; | ||
50 | |||
51 | struct da903x_chip_ops { | ||
52 | int (*init_chip)(struct da903x_chip *); | ||
53 | int (*unmask_events)(struct da903x_chip *, unsigned int events); | ||
54 | int (*mask_events)(struct da903x_chip *, unsigned int events); | ||
55 | int (*read_events)(struct da903x_chip *, unsigned int *events); | ||
56 | int (*read_status)(struct da903x_chip *, unsigned int *status); | ||
57 | }; | ||
58 | |||
59 | struct da903x_chip { | ||
60 | struct i2c_client *client; | ||
61 | struct device *dev; | ||
62 | struct da903x_chip_ops *ops; | ||
63 | |||
64 | int type; | ||
65 | uint32_t events_mask; | ||
66 | |||
67 | struct mutex lock; | ||
68 | struct work_struct irq_work; | ||
69 | |||
70 | struct blocking_notifier_head notifier_list; | ||
71 | }; | ||
72 | |||
73 | static inline int __da903x_read(struct i2c_client *client, | ||
74 | int reg, uint8_t *val) | ||
75 | { | ||
76 | int ret; | ||
77 | |||
78 | ret = i2c_smbus_read_byte_data(client, reg); | ||
79 | if (ret < 0) { | ||
80 | dev_err(&client->dev, "failed reading at 0x%02x\n", reg); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | *val = (uint8_t)ret; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static inline int __da903x_reads(struct i2c_client *client, int reg, | ||
89 | int len, uint8_t *val) | ||
90 | { | ||
91 | int ret; | ||
92 | |||
93 | ret = i2c_smbus_read_i2c_block_data(client, reg, len, val); | ||
94 | if (ret < 0) { | ||
95 | dev_err(&client->dev, "failed reading from 0x%02x\n", reg); | ||
96 | return ret; | ||
97 | } | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static inline int __da903x_write(struct i2c_client *client, | ||
102 | int reg, uint8_t val) | ||
103 | { | ||
104 | int ret; | ||
105 | |||
106 | ret = i2c_smbus_write_byte_data(client, reg, val); | ||
107 | if (ret < 0) { | ||
108 | dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n", | ||
109 | val, reg); | ||
110 | return ret; | ||
111 | } | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static inline int __da903x_writes(struct i2c_client *client, int reg, | ||
116 | int len, uint8_t *val) | ||
117 | { | ||
118 | int ret; | ||
119 | |||
120 | ret = i2c_smbus_write_i2c_block_data(client, reg, len, val); | ||
121 | if (ret < 0) { | ||
122 | dev_err(&client->dev, "failed writings to 0x%02x\n", reg); | ||
123 | return ret; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | int da903x_register_notifier(struct device *dev, struct notifier_block *nb, | ||
129 | unsigned int events) | ||
130 | { | ||
131 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
132 | |||
133 | chip->ops->unmask_events(chip, events); | ||
134 | return blocking_notifier_chain_register(&chip->notifier_list, nb); | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(da903x_register_notifier); | ||
137 | |||
138 | int da903x_unregister_notifier(struct device *dev, struct notifier_block *nb, | ||
139 | unsigned int events) | ||
140 | { | ||
141 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
142 | |||
143 | chip->ops->mask_events(chip, events); | ||
144 | return blocking_notifier_chain_unregister(&chip->notifier_list, nb); | ||
145 | } | ||
146 | EXPORT_SYMBOL_GPL(da903x_unregister_notifier); | ||
147 | |||
148 | int da903x_write(struct device *dev, int reg, uint8_t val) | ||
149 | { | ||
150 | return __da903x_write(to_i2c_client(dev), reg, val); | ||
151 | } | ||
152 | EXPORT_SYMBOL_GPL(da903x_write); | ||
153 | |||
154 | int da903x_read(struct device *dev, int reg, uint8_t *val) | ||
155 | { | ||
156 | return __da903x_read(to_i2c_client(dev), reg, val); | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(da903x_read); | ||
159 | |||
160 | int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
161 | { | ||
162 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
163 | uint8_t reg_val; | ||
164 | int ret = 0; | ||
165 | |||
166 | mutex_lock(&chip->lock); | ||
167 | |||
168 | ret = __da903x_read(chip->client, reg, ®_val); | ||
169 | if (ret) | ||
170 | goto out; | ||
171 | |||
172 | if ((reg_val & bit_mask) == 0) { | ||
173 | reg_val |= bit_mask; | ||
174 | ret = __da903x_write(chip->client, reg, reg_val); | ||
175 | } | ||
176 | out: | ||
177 | mutex_unlock(&chip->lock); | ||
178 | return ret; | ||
179 | } | ||
180 | EXPORT_SYMBOL_GPL(da903x_set_bits); | ||
181 | |||
182 | int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
183 | { | ||
184 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
185 | uint8_t reg_val; | ||
186 | int ret = 0; | ||
187 | |||
188 | mutex_lock(&chip->lock); | ||
189 | |||
190 | ret = __da903x_read(chip->client, reg, ®_val); | ||
191 | if (ret) | ||
192 | goto out; | ||
193 | |||
194 | if (reg_val & bit_mask) { | ||
195 | reg_val &= ~bit_mask; | ||
196 | ret = __da903x_write(chip->client, reg, reg_val); | ||
197 | } | ||
198 | out: | ||
199 | mutex_unlock(&chip->lock); | ||
200 | return ret; | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(da903x_clr_bits); | ||
203 | |||
204 | int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask) | ||
205 | { | ||
206 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
207 | uint8_t reg_val; | ||
208 | int ret = 0; | ||
209 | |||
210 | mutex_lock(&chip->lock); | ||
211 | |||
212 | ret = __da903x_read(chip->client, reg, ®_val); | ||
213 | if (ret) | ||
214 | goto out; | ||
215 | |||
216 | if ((reg_val & mask) != val) { | ||
217 | reg_val = (reg_val & ~mask) | val; | ||
218 | ret = __da903x_write(chip->client, reg, reg_val); | ||
219 | } | ||
220 | out: | ||
221 | mutex_unlock(&chip->lock); | ||
222 | return ret; | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(da903x_update); | ||
225 | |||
226 | int da903x_query_status(struct device *dev, unsigned int sbits) | ||
227 | { | ||
228 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
229 | unsigned int status = 0; | ||
230 | |||
231 | chip->ops->read_status(chip, &status); | ||
232 | return ((status & sbits) == sbits); | ||
233 | } | ||
234 | EXPORT_SYMBOL(da903x_query_status); | ||
235 | |||
236 | static int __devinit da9030_init_chip(struct da903x_chip *chip) | ||
237 | { | ||
238 | uint8_t chip_id; | ||
239 | int err; | ||
240 | |||
241 | err = __da903x_read(chip->client, DA9030_CHIP_ID, &chip_id); | ||
242 | if (err) | ||
243 | return err; | ||
244 | |||
245 | err = __da903x_write(chip->client, DA9030_SYS_CTRL_A, 0xE8); | ||
246 | if (err) | ||
247 | return err; | ||
248 | |||
249 | dev_info(chip->dev, "DA9030 (CHIP ID: 0x%02x) detected\n", chip_id); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int da9030_unmask_events(struct da903x_chip *chip, unsigned int events) | ||
254 | { | ||
255 | uint8_t v[3]; | ||
256 | |||
257 | chip->events_mask &= ~events; | ||
258 | |||
259 | v[0] = (chip->events_mask & 0xff); | ||
260 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
261 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
262 | |||
263 | return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v); | ||
264 | } | ||
265 | |||
266 | static int da9030_mask_events(struct da903x_chip *chip, unsigned int events) | ||
267 | { | ||
268 | uint8_t v[3]; | ||
269 | |||
270 | chip->events_mask &= ~events; | ||
271 | |||
272 | v[0] = (chip->events_mask & 0xff); | ||
273 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
274 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
275 | |||
276 | return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v); | ||
277 | } | ||
278 | |||
279 | static int da9030_read_events(struct da903x_chip *chip, unsigned int *events) | ||
280 | { | ||
281 | uint8_t v[3] = {0, 0, 0}; | ||
282 | int ret; | ||
283 | |||
284 | ret = __da903x_reads(chip->client, DA9030_EVENT_A, 3, v); | ||
285 | if (ret < 0) | ||
286 | return ret; | ||
287 | |||
288 | *events = (v[2] << 16) | (v[1] << 8) | v[0]; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int da9030_read_status(struct da903x_chip *chip, unsigned int *status) | ||
293 | { | ||
294 | return __da903x_read(chip->client, DA9030_STATUS, (uint8_t *)status); | ||
295 | } | ||
296 | |||
297 | static int da9034_init_chip(struct da903x_chip *chip) | ||
298 | { | ||
299 | uint8_t chip_id; | ||
300 | int err; | ||
301 | |||
302 | err = __da903x_read(chip->client, DA9034_CHIP_ID, &chip_id); | ||
303 | if (err) | ||
304 | return err; | ||
305 | |||
306 | err = __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0xE8); | ||
307 | if (err) | ||
308 | return err; | ||
309 | |||
310 | /* avoid SRAM power off during sleep*/ | ||
311 | __da903x_write(chip->client, 0x10, 0x07); | ||
312 | __da903x_write(chip->client, 0x11, 0xff); | ||
313 | __da903x_write(chip->client, 0x12, 0xff); | ||
314 | |||
315 | /* Enable the ONKEY power down functionality */ | ||
316 | __da903x_write(chip->client, DA9034_SYS_CTRL_B, 0x20); | ||
317 | __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0x60); | ||
318 | |||
319 | /* workaround to make LEDs work */ | ||
320 | __da903x_write(chip->client, 0x90, 0x01); | ||
321 | __da903x_write(chip->client, 0xB0, 0x08); | ||
322 | |||
323 | /* make ADTV1 and SDTV1 effective */ | ||
324 | __da903x_write(chip->client, 0x20, 0x00); | ||
325 | |||
326 | dev_info(chip->dev, "DA9034 (CHIP ID: 0x%02x) detected\n", chip_id); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int da9034_unmask_events(struct da903x_chip *chip, unsigned int events) | ||
331 | { | ||
332 | uint8_t v[4]; | ||
333 | |||
334 | chip->events_mask &= ~events; | ||
335 | |||
336 | v[0] = (chip->events_mask & 0xff); | ||
337 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
338 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
339 | v[3] = (chip->events_mask >> 24) & 0xff; | ||
340 | |||
341 | return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v); | ||
342 | } | ||
343 | |||
344 | static int da9034_mask_events(struct da903x_chip *chip, unsigned int events) | ||
345 | { | ||
346 | uint8_t v[4]; | ||
347 | |||
348 | chip->events_mask |= events; | ||
349 | |||
350 | v[0] = (chip->events_mask & 0xff); | ||
351 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
352 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
353 | v[3] = (chip->events_mask >> 24) & 0xff; | ||
354 | |||
355 | return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v); | ||
356 | } | ||
357 | |||
358 | static int da9034_read_events(struct da903x_chip *chip, unsigned int *events) | ||
359 | { | ||
360 | uint8_t v[4] = {0, 0, 0, 0}; | ||
361 | int ret; | ||
362 | |||
363 | ret = __da903x_reads(chip->client, DA9034_EVENT_A, 4, v); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | |||
367 | *events = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0]; | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int da9034_read_status(struct da903x_chip *chip, unsigned int *status) | ||
372 | { | ||
373 | uint8_t v[2] = {0, 0}; | ||
374 | int ret = 0; | ||
375 | |||
376 | ret = __da903x_reads(chip->client, DA9034_STATUS_A, 2, v); | ||
377 | if (ret) | ||
378 | return ret; | ||
379 | |||
380 | *status = (v[1] << 8) | v[0]; | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static void da903x_irq_work(struct work_struct *work) | ||
385 | { | ||
386 | struct da903x_chip *chip = | ||
387 | container_of(work, struct da903x_chip, irq_work); | ||
388 | unsigned int events = 0; | ||
389 | |||
390 | while (1) { | ||
391 | if (chip->ops->read_events(chip, &events)) | ||
392 | break; | ||
393 | |||
394 | events &= ~chip->events_mask; | ||
395 | if (events == 0) | ||
396 | break; | ||
397 | |||
398 | blocking_notifier_call_chain( | ||
399 | &chip->notifier_list, events, NULL); | ||
400 | } | ||
401 | enable_irq(chip->client->irq); | ||
402 | } | ||
403 | |||
404 | static int da903x_irq_handler(int irq, void *data) | ||
405 | { | ||
406 | struct da903x_chip *chip = data; | ||
407 | |||
408 | disable_irq_nosync(irq); | ||
409 | (void)schedule_work(&chip->irq_work); | ||
410 | |||
411 | return IRQ_HANDLED; | ||
412 | } | ||
413 | |||
414 | static struct da903x_chip_ops da903x_ops[] = { | ||
415 | [0] = { | ||
416 | .init_chip = da9030_init_chip, | ||
417 | .unmask_events = da9030_unmask_events, | ||
418 | .mask_events = da9030_mask_events, | ||
419 | .read_events = da9030_read_events, | ||
420 | .read_status = da9030_read_status, | ||
421 | }, | ||
422 | [1] = { | ||
423 | .init_chip = da9034_init_chip, | ||
424 | .unmask_events = da9034_unmask_events, | ||
425 | .mask_events = da9034_mask_events, | ||
426 | .read_events = da9034_read_events, | ||
427 | .read_status = da9034_read_status, | ||
428 | } | ||
429 | }; | ||
430 | |||
431 | static const struct i2c_device_id da903x_id_table[] = { | ||
432 | { "da9030", 0 }, | ||
433 | { "da9034", 1 }, | ||
434 | { }, | ||
435 | }; | ||
436 | MODULE_DEVICE_TABLE(i2c, da903x_id_table); | ||
437 | |||
438 | static int __devexit __remove_subdev(struct device *dev, void *unused) | ||
439 | { | ||
440 | platform_device_unregister(to_platform_device(dev)); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int __devexit da903x_remove_subdevs(struct da903x_chip *chip) | ||
445 | { | ||
446 | return device_for_each_child(chip->dev, NULL, __remove_subdev); | ||
447 | } | ||
448 | |||
449 | static int __devinit da903x_add_subdevs(struct da903x_chip *chip, | ||
450 | struct da903x_platform_data *pdata) | ||
451 | { | ||
452 | struct da903x_subdev_info *subdev; | ||
453 | struct platform_device *pdev; | ||
454 | int i, ret = 0; | ||
455 | |||
456 | for (i = 0; i < pdata->num_subdevs; i++) { | ||
457 | subdev = &pdata->subdevs[i]; | ||
458 | |||
459 | pdev = platform_device_alloc(subdev->name, subdev->id); | ||
460 | |||
461 | pdev->dev.parent = chip->dev; | ||
462 | pdev->dev.platform_data = subdev->platform_data; | ||
463 | |||
464 | ret = platform_device_add(pdev); | ||
465 | if (ret) | ||
466 | goto failed; | ||
467 | } | ||
468 | return 0; | ||
469 | |||
470 | failed: | ||
471 | da903x_remove_subdevs(chip); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | static int __devinit da903x_probe(struct i2c_client *client, | ||
476 | const struct i2c_device_id *id) | ||
477 | { | ||
478 | struct da903x_platform_data *pdata = client->dev.platform_data; | ||
479 | struct da903x_chip *chip; | ||
480 | unsigned int tmp; | ||
481 | int ret; | ||
482 | |||
483 | chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL); | ||
484 | if (chip == NULL) | ||
485 | return -ENOMEM; | ||
486 | |||
487 | chip->client = client; | ||
488 | chip->dev = &client->dev; | ||
489 | chip->ops = &da903x_ops[id->driver_data]; | ||
490 | |||
491 | mutex_init(&chip->lock); | ||
492 | INIT_WORK(&chip->irq_work, da903x_irq_work); | ||
493 | BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list); | ||
494 | |||
495 | i2c_set_clientdata(client, chip); | ||
496 | |||
497 | ret = chip->ops->init_chip(chip); | ||
498 | if (ret) | ||
499 | goto out_free_chip; | ||
500 | |||
501 | /* mask and clear all IRQs */ | ||
502 | chip->events_mask = 0xffffffff; | ||
503 | chip->ops->mask_events(chip, chip->events_mask); | ||
504 | chip->ops->read_events(chip, &tmp); | ||
505 | |||
506 | ret = request_irq(client->irq, da903x_irq_handler, | ||
507 | IRQF_DISABLED | IRQF_TRIGGER_FALLING, | ||
508 | "da903x", chip); | ||
509 | if (ret) { | ||
510 | dev_err(&client->dev, "failed to request irq %d\n", | ||
511 | client->irq); | ||
512 | goto out_free_chip; | ||
513 | } | ||
514 | |||
515 | ret = da903x_add_subdevs(chip, pdata); | ||
516 | if (ret) | ||
517 | goto out_free_irq; | ||
518 | |||
519 | return 0; | ||
520 | |||
521 | out_free_irq: | ||
522 | free_irq(client->irq, chip); | ||
523 | out_free_chip: | ||
524 | i2c_set_clientdata(client, NULL); | ||
525 | kfree(chip); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | static int __devexit da903x_remove(struct i2c_client *client) | ||
530 | { | ||
531 | struct da903x_chip *chip = i2c_get_clientdata(client); | ||
532 | |||
533 | da903x_remove_subdevs(chip); | ||
534 | kfree(chip); | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static struct i2c_driver da903x_driver = { | ||
539 | .driver = { | ||
540 | .name = "da903x", | ||
541 | .owner = THIS_MODULE, | ||
542 | }, | ||
543 | .probe = da903x_probe, | ||
544 | .remove = __devexit_p(da903x_remove), | ||
545 | .id_table = da903x_id_table, | ||
546 | }; | ||
547 | |||
548 | static int __init da903x_init(void) | ||
549 | { | ||
550 | return i2c_add_driver(&da903x_driver); | ||
551 | } | ||
552 | module_init(da903x_init); | ||
553 | |||
554 | static void __exit da903x_exit(void) | ||
555 | { | ||
556 | i2c_del_driver(&da903x_driver); | ||
557 | } | ||
558 | module_exit(da903x_exit); | ||
559 | |||
560 | MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034"); | ||
561 | MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>" | ||
562 | "Mike Rapoport <mike@compulab.co.il>"); | ||
563 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index 8872cc077519..1a4d04664d6d 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c | |||
@@ -112,7 +112,7 @@ static void egpio_handler(unsigned int irq, struct irq_desc *desc) | |||
112 | /* Run irq handler */ | 112 | /* Run irq handler */ |
113 | pr_debug("got IRQ %d\n", irqpin); | 113 | pr_debug("got IRQ %d\n", irqpin); |
114 | irq = ei->irq_start + irqpin; | 114 | irq = ei->irq_start + irqpin; |
115 | desc = &irq_desc[irq]; | 115 | desc = irq_to_desc(irq); |
116 | desc->handle_irq(irq, desc); | 116 | desc->handle_irq(irq, desc); |
117 | } | 117 | } |
118 | } | 118 | } |
@@ -289,7 +289,7 @@ static int __init egpio_probe(struct platform_device *pdev) | |||
289 | ei->base_addr = ioremap_nocache(res->start, res->end - res->start); | 289 | ei->base_addr = ioremap_nocache(res->start, res->end - res->start); |
290 | if (!ei->base_addr) | 290 | if (!ei->base_addr) |
291 | goto fail; | 291 | goto fail; |
292 | pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr); | 292 | pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr); |
293 | 293 | ||
294 | if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) | 294 | if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) |
295 | goto fail; | 295 | goto fail; |
@@ -318,6 +318,8 @@ static int __init egpio_probe(struct platform_device *pdev) | |||
318 | ei->chip[i].dev = &(pdev->dev); | 318 | ei->chip[i].dev = &(pdev->dev); |
319 | chip = &(ei->chip[i].chip); | 319 | chip = &(ei->chip[i].chip); |
320 | chip->label = "htc-egpio"; | 320 | chip->label = "htc-egpio"; |
321 | chip->dev = &pdev->dev; | ||
322 | chip->owner = THIS_MODULE; | ||
321 | chip->get = egpio_get; | 323 | chip->get = egpio_get; |
322 | chip->set = egpio_set; | 324 | chip->set = egpio_set; |
323 | chip->direction_input = egpio_direction_input; | 325 | chip->direction_input = egpio_direction_input; |
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 633cbba072f0..91b294dcc133 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c | |||
@@ -238,6 +238,8 @@ static int pasic3_remove(struct platform_device *pdev) | |||
238 | return 0; | 238 | return 0; |
239 | } | 239 | } |
240 | 240 | ||
241 | MODULE_ALIAS("platform:pasic3"); | ||
242 | |||
241 | static struct platform_driver pasic3_driver = { | 243 | static struct platform_driver pasic3_driver = { |
242 | .driver = { | 244 | .driver = { |
243 | .name = "pasic3", | 245 | .name = "pasic3", |
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 1eab7cffceaa..28380b20bc70 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c | |||
@@ -21,12 +21,12 @@ | |||
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | 22 | ||
23 | #include <asm/dma.h> | 23 | #include <asm/dma.h> |
24 | #include <asm/hardware.h> | 24 | #include <mach/hardware.h> |
25 | #include <asm/mach-types.h> | 25 | #include <asm/mach-types.h> |
26 | #include <asm/system.h> | 26 | #include <asm/system.h> |
27 | #include <asm/arch/mcp.h> | 27 | #include <mach/mcp.h> |
28 | 28 | ||
29 | #include <asm/arch/assabet.h> | 29 | #include <mach/assabet.h> |
30 | 30 | ||
31 | #include "mcp.h" | 31 | #include "mcp.h" |
32 | 32 | ||
@@ -242,6 +242,8 @@ static int mcp_sa11x0_resume(struct platform_device *dev) | |||
242 | /* | 242 | /* |
243 | * The driver for the SA11x0 MCP port. | 243 | * The driver for the SA11x0 MCP port. |
244 | */ | 244 | */ |
245 | MODULE_ALIAS("platform:sa11x0-mcp"); | ||
246 | |||
245 | static struct platform_driver mcp_sa11x0_driver = { | 247 | static struct platform_driver mcp_sa11x0_driver = { |
246 | .probe = mcp_sa11x0_probe, | 248 | .probe = mcp_sa11x0_probe, |
247 | .remove = mcp_sa11x0_remove, | 249 | .remove = mcp_sa11x0_remove, |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c new file mode 100644 index 000000000000..6c0d1bec4b76 --- /dev/null +++ b/drivers/mfd/mfd-core.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * drivers/mfd/mfd-core.c | ||
3 | * | ||
4 | * core MFD support | ||
5 | * Copyright (c) 2006 Ian Molton | ||
6 | * Copyright (c) 2007,2008 Dmitry Baryshkov | ||
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 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/mfd/core.h> | ||
17 | |||
18 | static int mfd_add_device(struct device *parent, int id, | ||
19 | const struct mfd_cell *cell, | ||
20 | struct resource *mem_base, | ||
21 | int irq_base) | ||
22 | { | ||
23 | struct resource *res; | ||
24 | struct platform_device *pdev; | ||
25 | int ret = -ENOMEM; | ||
26 | int r; | ||
27 | |||
28 | pdev = platform_device_alloc(cell->name, id); | ||
29 | if (!pdev) | ||
30 | goto fail_alloc; | ||
31 | |||
32 | res = kzalloc(sizeof(*res) * cell->num_resources, GFP_KERNEL); | ||
33 | if (!res) | ||
34 | goto fail_device; | ||
35 | |||
36 | pdev->dev.parent = parent; | ||
37 | |||
38 | ret = platform_device_add_data(pdev, | ||
39 | cell->platform_data, cell->data_size); | ||
40 | if (ret) | ||
41 | goto fail_res; | ||
42 | |||
43 | for (r = 0; r < cell->num_resources; r++) { | ||
44 | res[r].name = cell->resources[r].name; | ||
45 | res[r].flags = cell->resources[r].flags; | ||
46 | |||
47 | /* Find out base to use */ | ||
48 | if (cell->resources[r].flags & IORESOURCE_MEM) { | ||
49 | res[r].parent = mem_base; | ||
50 | res[r].start = mem_base->start + | ||
51 | cell->resources[r].start; | ||
52 | res[r].end = mem_base->start + | ||
53 | cell->resources[r].end; | ||
54 | } else if (cell->resources[r].flags & IORESOURCE_IRQ) { | ||
55 | res[r].start = irq_base + | ||
56 | cell->resources[r].start; | ||
57 | res[r].end = irq_base + | ||
58 | cell->resources[r].end; | ||
59 | } else { | ||
60 | res[r].parent = cell->resources[r].parent; | ||
61 | res[r].start = cell->resources[r].start; | ||
62 | res[r].end = cell->resources[r].end; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | platform_device_add_resources(pdev, res, cell->num_resources); | ||
67 | |||
68 | ret = platform_device_add(pdev); | ||
69 | if (ret) | ||
70 | goto fail_res; | ||
71 | |||
72 | kfree(res); | ||
73 | |||
74 | return 0; | ||
75 | |||
76 | /* platform_device_del(pdev); */ | ||
77 | fail_res: | ||
78 | kfree(res); | ||
79 | fail_device: | ||
80 | platform_device_put(pdev); | ||
81 | fail_alloc: | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | int mfd_add_devices(struct device *parent, int id, | ||
86 | const struct mfd_cell *cells, int n_devs, | ||
87 | struct resource *mem_base, | ||
88 | int irq_base) | ||
89 | { | ||
90 | int i; | ||
91 | int ret = 0; | ||
92 | |||
93 | for (i = 0; i < n_devs; i++) { | ||
94 | ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); | ||
95 | if (ret) | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | if (ret) | ||
100 | mfd_remove_devices(parent); | ||
101 | |||
102 | return ret; | ||
103 | } | ||
104 | EXPORT_SYMBOL(mfd_add_devices); | ||
105 | |||
106 | static int mfd_remove_devices_fn(struct device *dev, void *unused) | ||
107 | { | ||
108 | platform_device_unregister(to_platform_device(dev)); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | void mfd_remove_devices(struct device *parent) | ||
113 | { | ||
114 | device_for_each_child(parent, NULL, mfd_remove_devices_fn); | ||
115 | } | ||
116 | EXPORT_SYMBOL(mfd_remove_devices); | ||
117 | |||
118 | MODULE_LICENSE("GPL"); | ||
119 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); | ||
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 2fe64734d8af..170f9d47c2f9 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | #include <linux/i2c-gpio.h> | ||
22 | 23 | ||
23 | #include <linux/sm501.h> | 24 | #include <linux/sm501.h> |
24 | #include <linux/sm501-regs.h> | 25 | #include <linux/sm501-regs.h> |
@@ -31,10 +32,37 @@ struct sm501_device { | |||
31 | struct platform_device pdev; | 32 | struct platform_device pdev; |
32 | }; | 33 | }; |
33 | 34 | ||
35 | struct sm501_gpio; | ||
36 | |||
37 | #ifdef CONFIG_MFD_SM501_GPIO | ||
38 | #include <linux/gpio.h> | ||
39 | |||
40 | struct sm501_gpio_chip { | ||
41 | struct gpio_chip gpio; | ||
42 | struct sm501_gpio *ourgpio; /* to get back to parent. */ | ||
43 | void __iomem *regbase; | ||
44 | }; | ||
45 | |||
46 | struct sm501_gpio { | ||
47 | struct sm501_gpio_chip low; | ||
48 | struct sm501_gpio_chip high; | ||
49 | spinlock_t lock; | ||
50 | |||
51 | unsigned int registered : 1; | ||
52 | void __iomem *regs; | ||
53 | struct resource *regs_res; | ||
54 | }; | ||
55 | #else | ||
56 | struct sm501_gpio { | ||
57 | /* no gpio support, empty definition for sm501_devdata. */ | ||
58 | }; | ||
59 | #endif | ||
60 | |||
34 | struct sm501_devdata { | 61 | struct sm501_devdata { |
35 | spinlock_t reg_lock; | 62 | spinlock_t reg_lock; |
36 | struct mutex clock_lock; | 63 | struct mutex clock_lock; |
37 | struct list_head devices; | 64 | struct list_head devices; |
65 | struct sm501_gpio gpio; | ||
38 | 66 | ||
39 | struct device *dev; | 67 | struct device *dev; |
40 | struct resource *io_res; | 68 | struct resource *io_res; |
@@ -42,6 +70,7 @@ struct sm501_devdata { | |||
42 | struct resource *regs_claim; | 70 | struct resource *regs_claim; |
43 | struct sm501_platdata *platdata; | 71 | struct sm501_platdata *platdata; |
44 | 72 | ||
73 | |||
45 | unsigned int in_suspend; | 74 | unsigned int in_suspend; |
46 | unsigned long pm_misc; | 75 | unsigned long pm_misc; |
47 | 76 | ||
@@ -52,6 +81,7 @@ struct sm501_devdata { | |||
52 | unsigned int rev; | 81 | unsigned int rev; |
53 | }; | 82 | }; |
54 | 83 | ||
84 | |||
55 | #define MHZ (1000 * 1000) | 85 | #define MHZ (1000 * 1000) |
56 | 86 | ||
57 | #ifdef DEBUG | 87 | #ifdef DEBUG |
@@ -276,58 +306,6 @@ unsigned long sm501_modify_reg(struct device *dev, | |||
276 | 306 | ||
277 | EXPORT_SYMBOL_GPL(sm501_modify_reg); | 307 | EXPORT_SYMBOL_GPL(sm501_modify_reg); |
278 | 308 | ||
279 | unsigned long sm501_gpio_get(struct device *dev, | ||
280 | unsigned long gpio) | ||
281 | { | ||
282 | struct sm501_devdata *sm = dev_get_drvdata(dev); | ||
283 | unsigned long result; | ||
284 | unsigned long reg; | ||
285 | |||
286 | reg = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW; | ||
287 | result = readl(sm->regs + reg); | ||
288 | |||
289 | result >>= (gpio & 31); | ||
290 | return result & 1UL; | ||
291 | } | ||
292 | |||
293 | EXPORT_SYMBOL_GPL(sm501_gpio_get); | ||
294 | |||
295 | void sm501_gpio_set(struct device *dev, | ||
296 | unsigned long gpio, | ||
297 | unsigned int to, | ||
298 | unsigned int dir) | ||
299 | { | ||
300 | struct sm501_devdata *sm = dev_get_drvdata(dev); | ||
301 | |||
302 | unsigned long bit = 1 << (gpio & 31); | ||
303 | unsigned long base; | ||
304 | unsigned long save; | ||
305 | unsigned long val; | ||
306 | |||
307 | base = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW; | ||
308 | base += SM501_GPIO; | ||
309 | |||
310 | spin_lock_irqsave(&sm->reg_lock, save); | ||
311 | |||
312 | val = readl(sm->regs + base) & ~bit; | ||
313 | if (to) | ||
314 | val |= bit; | ||
315 | writel(val, sm->regs + base); | ||
316 | |||
317 | val = readl(sm->regs + SM501_GPIO_DDR_LOW) & ~bit; | ||
318 | if (dir) | ||
319 | val |= bit; | ||
320 | |||
321 | writel(val, sm->regs + SM501_GPIO_DDR_LOW); | ||
322 | sm501_sync_regs(sm); | ||
323 | |||
324 | spin_unlock_irqrestore(&sm->reg_lock, save); | ||
325 | |||
326 | } | ||
327 | |||
328 | EXPORT_SYMBOL_GPL(sm501_gpio_set); | ||
329 | |||
330 | |||
331 | /* sm501_unit_power | 309 | /* sm501_unit_power |
332 | * | 310 | * |
333 | * alters the power active gate to set specific units on or off | 311 | * alters the power active gate to set specific units on or off |
@@ -645,8 +623,8 @@ unsigned long sm501_set_clock(struct device *dev, | |||
645 | 623 | ||
646 | sm501_sync_regs(sm); | 624 | sm501_sync_regs(sm); |
647 | 625 | ||
648 | dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", | 626 | dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", |
649 | gate, clock, mode); | 627 | gate, clock, mode); |
650 | 628 | ||
651 | sm501_mdelay(sm, 16); | 629 | sm501_mdelay(sm, 16); |
652 | mutex_unlock(&sm->clock_lock); | 630 | mutex_unlock(&sm->clock_lock); |
@@ -764,7 +742,7 @@ static int sm501_register_device(struct sm501_devdata *sm, | |||
764 | int ret; | 742 | int ret; |
765 | 743 | ||
766 | for (ptr = 0; ptr < pdev->num_resources; ptr++) { | 744 | for (ptr = 0; ptr < pdev->num_resources; ptr++) { |
767 | printk("%s[%d] flags %08lx: %08llx..%08llx\n", | 745 | printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n", |
768 | pdev->name, ptr, | 746 | pdev->name, ptr, |
769 | pdev->resource[ptr].flags, | 747 | pdev->resource[ptr].flags, |
770 | (unsigned long long)pdev->resource[ptr].start, | 748 | (unsigned long long)pdev->resource[ptr].start, |
@@ -906,6 +884,313 @@ static int sm501_register_display(struct sm501_devdata *sm, | |||
906 | return sm501_register_device(sm, pdev); | 884 | return sm501_register_device(sm, pdev); |
907 | } | 885 | } |
908 | 886 | ||
887 | #ifdef CONFIG_MFD_SM501_GPIO | ||
888 | |||
889 | static inline struct sm501_gpio_chip *to_sm501_gpio(struct gpio_chip *gc) | ||
890 | { | ||
891 | return container_of(gc, struct sm501_gpio_chip, gpio); | ||
892 | } | ||
893 | |||
894 | static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio) | ||
895 | { | ||
896 | return container_of(gpio, struct sm501_devdata, gpio); | ||
897 | } | ||
898 | |||
899 | static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
900 | |||
901 | { | ||
902 | struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip); | ||
903 | unsigned long result; | ||
904 | |||
905 | result = readl(smgpio->regbase + SM501_GPIO_DATA_LOW); | ||
906 | result >>= offset; | ||
907 | |||
908 | return result & 1UL; | ||
909 | } | ||
910 | |||
911 | static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
912 | |||
913 | { | ||
914 | struct sm501_gpio_chip *smchip = to_sm501_gpio(chip); | ||
915 | struct sm501_gpio *smgpio = smchip->ourgpio; | ||
916 | unsigned long bit = 1 << offset; | ||
917 | void __iomem *regs = smchip->regbase; | ||
918 | unsigned long save; | ||
919 | unsigned long val; | ||
920 | |||
921 | dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n", | ||
922 | __func__, chip, offset); | ||
923 | |||
924 | spin_lock_irqsave(&smgpio->lock, save); | ||
925 | |||
926 | val = readl(regs + SM501_GPIO_DATA_LOW) & ~bit; | ||
927 | if (value) | ||
928 | val |= bit; | ||
929 | writel(val, regs); | ||
930 | |||
931 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | ||
932 | spin_unlock_irqrestore(&smgpio->lock, save); | ||
933 | } | ||
934 | |||
935 | static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) | ||
936 | { | ||
937 | struct sm501_gpio_chip *smchip = to_sm501_gpio(chip); | ||
938 | struct sm501_gpio *smgpio = smchip->ourgpio; | ||
939 | void __iomem *regs = smchip->regbase; | ||
940 | unsigned long bit = 1 << offset; | ||
941 | unsigned long save; | ||
942 | unsigned long ddr; | ||
943 | |||
944 | dev_info(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n", | ||
945 | __func__, chip, offset); | ||
946 | |||
947 | spin_lock_irqsave(&smgpio->lock, save); | ||
948 | |||
949 | ddr = readl(regs + SM501_GPIO_DDR_LOW); | ||
950 | writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW); | ||
951 | |||
952 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | ||
953 | spin_unlock_irqrestore(&smgpio->lock, save); | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int sm501_gpio_output(struct gpio_chip *chip, | ||
959 | unsigned offset, int value) | ||
960 | { | ||
961 | struct sm501_gpio_chip *smchip = to_sm501_gpio(chip); | ||
962 | struct sm501_gpio *smgpio = smchip->ourgpio; | ||
963 | unsigned long bit = 1 << offset; | ||
964 | void __iomem *regs = smchip->regbase; | ||
965 | unsigned long save; | ||
966 | unsigned long val; | ||
967 | unsigned long ddr; | ||
968 | |||
969 | dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d,%d)\n", | ||
970 | __func__, chip, offset, value); | ||
971 | |||
972 | spin_lock_irqsave(&smgpio->lock, save); | ||
973 | |||
974 | val = readl(regs + SM501_GPIO_DATA_LOW); | ||
975 | if (value) | ||
976 | val |= bit; | ||
977 | else | ||
978 | val &= ~bit; | ||
979 | writel(val, regs); | ||
980 | |||
981 | ddr = readl(regs + SM501_GPIO_DDR_LOW); | ||
982 | writel(ddr | bit, regs + SM501_GPIO_DDR_LOW); | ||
983 | |||
984 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | ||
985 | writel(val, regs + SM501_GPIO_DATA_LOW); | ||
986 | |||
987 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | ||
988 | spin_unlock_irqrestore(&smgpio->lock, save); | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static struct gpio_chip gpio_chip_template = { | ||
994 | .ngpio = 32, | ||
995 | .direction_input = sm501_gpio_input, | ||
996 | .direction_output = sm501_gpio_output, | ||
997 | .set = sm501_gpio_set, | ||
998 | .get = sm501_gpio_get, | ||
999 | }; | ||
1000 | |||
1001 | static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm, | ||
1002 | struct sm501_gpio *gpio, | ||
1003 | struct sm501_gpio_chip *chip) | ||
1004 | { | ||
1005 | struct sm501_platdata *pdata = sm->platdata; | ||
1006 | struct gpio_chip *gchip = &chip->gpio; | ||
1007 | int base = pdata->gpio_base; | ||
1008 | |||
1009 | chip->gpio = gpio_chip_template; | ||
1010 | |||
1011 | if (chip == &gpio->high) { | ||
1012 | if (base > 0) | ||
1013 | base += 32; | ||
1014 | chip->regbase = gpio->regs + SM501_GPIO_DATA_HIGH; | ||
1015 | gchip->label = "SM501-HIGH"; | ||
1016 | } else { | ||
1017 | chip->regbase = gpio->regs + SM501_GPIO_DATA_LOW; | ||
1018 | gchip->label = "SM501-LOW"; | ||
1019 | } | ||
1020 | |||
1021 | gchip->base = base; | ||
1022 | chip->ourgpio = gpio; | ||
1023 | |||
1024 | return gpiochip_add(gchip); | ||
1025 | } | ||
1026 | |||
1027 | static int sm501_register_gpio(struct sm501_devdata *sm) | ||
1028 | { | ||
1029 | struct sm501_gpio *gpio = &sm->gpio; | ||
1030 | resource_size_t iobase = sm->io_res->start + SM501_GPIO; | ||
1031 | int ret; | ||
1032 | int tmp; | ||
1033 | |||
1034 | dev_dbg(sm->dev, "registering gpio block %08llx\n", | ||
1035 | (unsigned long long)iobase); | ||
1036 | |||
1037 | spin_lock_init(&gpio->lock); | ||
1038 | |||
1039 | gpio->regs_res = request_mem_region(iobase, 0x20, "sm501-gpio"); | ||
1040 | if (gpio->regs_res == NULL) { | ||
1041 | dev_err(sm->dev, "gpio: failed to request region\n"); | ||
1042 | return -ENXIO; | ||
1043 | } | ||
1044 | |||
1045 | gpio->regs = ioremap(iobase, 0x20); | ||
1046 | if (gpio->regs == NULL) { | ||
1047 | dev_err(sm->dev, "gpio: failed to remap registers\n"); | ||
1048 | ret = -ENXIO; | ||
1049 | goto err_claimed; | ||
1050 | } | ||
1051 | |||
1052 | /* Register both our chips. */ | ||
1053 | |||
1054 | ret = sm501_gpio_register_chip(sm, gpio, &gpio->low); | ||
1055 | if (ret) { | ||
1056 | dev_err(sm->dev, "failed to add low chip\n"); | ||
1057 | goto err_mapped; | ||
1058 | } | ||
1059 | |||
1060 | ret = sm501_gpio_register_chip(sm, gpio, &gpio->high); | ||
1061 | if (ret) { | ||
1062 | dev_err(sm->dev, "failed to add high chip\n"); | ||
1063 | goto err_low_chip; | ||
1064 | } | ||
1065 | |||
1066 | gpio->registered = 1; | ||
1067 | |||
1068 | return 0; | ||
1069 | |||
1070 | err_low_chip: | ||
1071 | tmp = gpiochip_remove(&gpio->low.gpio); | ||
1072 | if (tmp) { | ||
1073 | dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n"); | ||
1074 | return ret; | ||
1075 | } | ||
1076 | |||
1077 | err_mapped: | ||
1078 | iounmap(gpio->regs); | ||
1079 | |||
1080 | err_claimed: | ||
1081 | release_resource(gpio->regs_res); | ||
1082 | kfree(gpio->regs_res); | ||
1083 | |||
1084 | return ret; | ||
1085 | } | ||
1086 | |||
1087 | static void sm501_gpio_remove(struct sm501_devdata *sm) | ||
1088 | { | ||
1089 | struct sm501_gpio *gpio = &sm->gpio; | ||
1090 | int ret; | ||
1091 | |||
1092 | if (!sm->gpio.registered) | ||
1093 | return; | ||
1094 | |||
1095 | ret = gpiochip_remove(&gpio->low.gpio); | ||
1096 | if (ret) | ||
1097 | dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n"); | ||
1098 | |||
1099 | ret = gpiochip_remove(&gpio->high.gpio); | ||
1100 | if (ret) | ||
1101 | dev_err(sm->dev, "cannot remove high chip, cannot tidy up\n"); | ||
1102 | |||
1103 | iounmap(gpio->regs); | ||
1104 | release_resource(gpio->regs_res); | ||
1105 | kfree(gpio->regs_res); | ||
1106 | } | ||
1107 | |||
1108 | static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin) | ||
1109 | { | ||
1110 | struct sm501_gpio *gpio = &sm->gpio; | ||
1111 | int base = (pin < 32) ? gpio->low.gpio.base : gpio->high.gpio.base; | ||
1112 | |||
1113 | return (pin % 32) + base; | ||
1114 | } | ||
1115 | |||
1116 | static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) | ||
1117 | { | ||
1118 | return sm->gpio.registered; | ||
1119 | } | ||
1120 | #else | ||
1121 | static inline int sm501_register_gpio(struct sm501_devdata *sm) | ||
1122 | { | ||
1123 | return 0; | ||
1124 | } | ||
1125 | |||
1126 | static inline void sm501_gpio_remove(struct sm501_devdata *sm) | ||
1127 | { | ||
1128 | } | ||
1129 | |||
1130 | static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin) | ||
1131 | { | ||
1132 | return -1; | ||
1133 | } | ||
1134 | |||
1135 | static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) | ||
1136 | { | ||
1137 | return 0; | ||
1138 | } | ||
1139 | #endif | ||
1140 | |||
1141 | static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, | ||
1142 | struct sm501_platdata_gpio_i2c *iic) | ||
1143 | { | ||
1144 | struct i2c_gpio_platform_data *icd; | ||
1145 | struct platform_device *pdev; | ||
1146 | |||
1147 | pdev = sm501_create_subdev(sm, "i2c-gpio", 0, | ||
1148 | sizeof(struct i2c_gpio_platform_data)); | ||
1149 | if (!pdev) | ||
1150 | return -ENOMEM; | ||
1151 | |||
1152 | icd = pdev->dev.platform_data; | ||
1153 | |||
1154 | /* We keep the pin_sda and pin_scl fields relative in case the | ||
1155 | * same platform data is passed to >1 SM501. | ||
1156 | */ | ||
1157 | |||
1158 | icd->sda_pin = sm501_gpio_pin2nr(sm, iic->pin_sda); | ||
1159 | icd->scl_pin = sm501_gpio_pin2nr(sm, iic->pin_scl); | ||
1160 | icd->timeout = iic->timeout; | ||
1161 | icd->udelay = iic->udelay; | ||
1162 | |||
1163 | /* note, we can't use either of the pin numbers, as the i2c-gpio | ||
1164 | * driver uses the platform.id field to generate the bus number | ||
1165 | * to register with the i2c core; The i2c core doesn't have enough | ||
1166 | * entries to deal with anything we currently use. | ||
1167 | */ | ||
1168 | |||
1169 | pdev->id = iic->bus_num; | ||
1170 | |||
1171 | dev_info(sm->dev, "registering i2c-%d: sda=%d (%d), scl=%d (%d)\n", | ||
1172 | iic->bus_num, | ||
1173 | icd->sda_pin, iic->pin_sda, icd->scl_pin, iic->pin_scl); | ||
1174 | |||
1175 | return sm501_register_device(sm, pdev); | ||
1176 | } | ||
1177 | |||
1178 | static int sm501_register_gpio_i2c(struct sm501_devdata *sm, | ||
1179 | struct sm501_platdata *pdata) | ||
1180 | { | ||
1181 | struct sm501_platdata_gpio_i2c *iic = pdata->gpio_i2c; | ||
1182 | int index; | ||
1183 | int ret; | ||
1184 | |||
1185 | for (index = 0; index < pdata->gpio_i2c_nr; index++, iic++) { | ||
1186 | ret = sm501_register_gpio_i2c_instance(sm, iic); | ||
1187 | if (ret < 0) | ||
1188 | return ret; | ||
1189 | } | ||
1190 | |||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
909 | /* sm501_dbg_regs | 1194 | /* sm501_dbg_regs |
910 | * | 1195 | * |
911 | * Debug attribute to attach to parent device to show core registers | 1196 | * Debug attribute to attach to parent device to show core registers |
@@ -1013,6 +1298,7 @@ static unsigned int sm501_mem_local[] = { | |||
1013 | static int sm501_init_dev(struct sm501_devdata *sm) | 1298 | static int sm501_init_dev(struct sm501_devdata *sm) |
1014 | { | 1299 | { |
1015 | struct sm501_initdata *idata; | 1300 | struct sm501_initdata *idata; |
1301 | struct sm501_platdata *pdata; | ||
1016 | resource_size_t mem_avail; | 1302 | resource_size_t mem_avail; |
1017 | unsigned long dramctrl; | 1303 | unsigned long dramctrl; |
1018 | unsigned long devid; | 1304 | unsigned long devid; |
@@ -1051,7 +1337,9 @@ static int sm501_init_dev(struct sm501_devdata *sm) | |||
1051 | 1337 | ||
1052 | /* check to see if we have some device initialisation */ | 1338 | /* check to see if we have some device initialisation */ |
1053 | 1339 | ||
1054 | idata = sm->platdata ? sm->platdata->init : NULL; | 1340 | pdata = sm->platdata; |
1341 | idata = pdata ? pdata->init : NULL; | ||
1342 | |||
1055 | if (idata) { | 1343 | if (idata) { |
1056 | sm501_init_regs(sm, idata); | 1344 | sm501_init_regs(sm, idata); |
1057 | 1345 | ||
@@ -1059,6 +1347,15 @@ static int sm501_init_dev(struct sm501_devdata *sm) | |||
1059 | sm501_register_usbhost(sm, &mem_avail); | 1347 | sm501_register_usbhost(sm, &mem_avail); |
1060 | if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1)) | 1348 | if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1)) |
1061 | sm501_register_uart(sm, idata->devices); | 1349 | sm501_register_uart(sm, idata->devices); |
1350 | if (idata->devices & SM501_USE_GPIO) | ||
1351 | sm501_register_gpio(sm); | ||
1352 | } | ||
1353 | |||
1354 | if (pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { | ||
1355 | if (!sm501_gpio_isregistered(sm)) | ||
1356 | dev_err(sm->dev, "no gpio available for i2c gpio.\n"); | ||
1357 | else | ||
1358 | sm501_register_gpio_i2c(sm, pdata); | ||
1062 | } | 1359 | } |
1063 | 1360 | ||
1064 | ret = sm501_check_clocks(sm); | 1361 | ret = sm501_check_clocks(sm); |
@@ -1077,31 +1374,31 @@ static int sm501_init_dev(struct sm501_devdata *sm) | |||
1077 | static int sm501_plat_probe(struct platform_device *dev) | 1374 | static int sm501_plat_probe(struct platform_device *dev) |
1078 | { | 1375 | { |
1079 | struct sm501_devdata *sm; | 1376 | struct sm501_devdata *sm; |
1080 | int err; | 1377 | int ret; |
1081 | 1378 | ||
1082 | sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL); | 1379 | sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL); |
1083 | if (sm == NULL) { | 1380 | if (sm == NULL) { |
1084 | dev_err(&dev->dev, "no memory for device data\n"); | 1381 | dev_err(&dev->dev, "no memory for device data\n"); |
1085 | err = -ENOMEM; | 1382 | ret = -ENOMEM; |
1086 | goto err1; | 1383 | goto err1; |
1087 | } | 1384 | } |
1088 | 1385 | ||
1089 | sm->dev = &dev->dev; | 1386 | sm->dev = &dev->dev; |
1090 | sm->pdev_id = dev->id; | 1387 | sm->pdev_id = dev->id; |
1091 | sm->irq = platform_get_irq(dev, 0); | ||
1092 | sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1); | ||
1093 | sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
1094 | sm->platdata = dev->dev.platform_data; | 1388 | sm->platdata = dev->dev.platform_data; |
1095 | 1389 | ||
1096 | if (sm->irq < 0) { | 1390 | ret = platform_get_irq(dev, 0); |
1391 | if (ret < 0) { | ||
1097 | dev_err(&dev->dev, "failed to get irq resource\n"); | 1392 | dev_err(&dev->dev, "failed to get irq resource\n"); |
1098 | err = sm->irq; | ||
1099 | goto err_res; | 1393 | goto err_res; |
1100 | } | 1394 | } |
1395 | sm->irq = ret; | ||
1101 | 1396 | ||
1397 | sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1); | ||
1398 | sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
1102 | if (sm->io_res == NULL || sm->mem_res == NULL) { | 1399 | if (sm->io_res == NULL || sm->mem_res == NULL) { |
1103 | dev_err(&dev->dev, "failed to get IO resource\n"); | 1400 | dev_err(&dev->dev, "failed to get IO resource\n"); |
1104 | err = -ENOENT; | 1401 | ret = -ENOENT; |
1105 | goto err_res; | 1402 | goto err_res; |
1106 | } | 1403 | } |
1107 | 1404 | ||
@@ -1110,7 +1407,7 @@ static int sm501_plat_probe(struct platform_device *dev) | |||
1110 | 1407 | ||
1111 | if (sm->regs_claim == NULL) { | 1408 | if (sm->regs_claim == NULL) { |
1112 | dev_err(&dev->dev, "cannot claim registers\n"); | 1409 | dev_err(&dev->dev, "cannot claim registers\n"); |
1113 | err= -EBUSY; | 1410 | ret = -EBUSY; |
1114 | goto err_res; | 1411 | goto err_res; |
1115 | } | 1412 | } |
1116 | 1413 | ||
@@ -1121,7 +1418,7 @@ static int sm501_plat_probe(struct platform_device *dev) | |||
1121 | 1418 | ||
1122 | if (sm->regs == NULL) { | 1419 | if (sm->regs == NULL) { |
1123 | dev_err(&dev->dev, "cannot remap registers\n"); | 1420 | dev_err(&dev->dev, "cannot remap registers\n"); |
1124 | err = -EIO; | 1421 | ret = -EIO; |
1125 | goto err_claim; | 1422 | goto err_claim; |
1126 | } | 1423 | } |
1127 | 1424 | ||
@@ -1133,13 +1430,36 @@ static int sm501_plat_probe(struct platform_device *dev) | |||
1133 | err_res: | 1430 | err_res: |
1134 | kfree(sm); | 1431 | kfree(sm); |
1135 | err1: | 1432 | err1: |
1136 | return err; | 1433 | return ret; |
1137 | 1434 | ||
1138 | } | 1435 | } |
1139 | 1436 | ||
1140 | #ifdef CONFIG_PM | 1437 | #ifdef CONFIG_PM |
1438 | |||
1141 | /* power management support */ | 1439 | /* power management support */ |
1142 | 1440 | ||
1441 | static void sm501_set_power(struct sm501_devdata *sm, int on) | ||
1442 | { | ||
1443 | struct sm501_platdata *pd = sm->platdata; | ||
1444 | |||
1445 | if (pd == NULL) | ||
1446 | return; | ||
1447 | |||
1448 | if (pd->get_power) { | ||
1449 | if (pd->get_power(sm->dev) == on) { | ||
1450 | dev_dbg(sm->dev, "is already %d\n", on); | ||
1451 | return; | ||
1452 | } | ||
1453 | } | ||
1454 | |||
1455 | if (pd->set_power) { | ||
1456 | dev_dbg(sm->dev, "setting power to %d\n", on); | ||
1457 | |||
1458 | pd->set_power(sm->dev, on); | ||
1459 | sm501_mdelay(sm, 10); | ||
1460 | } | ||
1461 | } | ||
1462 | |||
1143 | static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state) | 1463 | static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state) |
1144 | { | 1464 | { |
1145 | struct sm501_devdata *sm = platform_get_drvdata(pdev); | 1465 | struct sm501_devdata *sm = platform_get_drvdata(pdev); |
@@ -1148,6 +1468,12 @@ static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state) | |||
1148 | sm->pm_misc = readl(sm->regs + SM501_MISC_CONTROL); | 1468 | sm->pm_misc = readl(sm->regs + SM501_MISC_CONTROL); |
1149 | 1469 | ||
1150 | sm501_dump_regs(sm); | 1470 | sm501_dump_regs(sm); |
1471 | |||
1472 | if (sm->platdata) { | ||
1473 | if (sm->platdata->flags & SM501_FLAG_SUSPEND_OFF) | ||
1474 | sm501_set_power(sm, 0); | ||
1475 | } | ||
1476 | |||
1151 | return 0; | 1477 | return 0; |
1152 | } | 1478 | } |
1153 | 1479 | ||
@@ -1155,6 +1481,8 @@ static int sm501_plat_resume(struct platform_device *pdev) | |||
1155 | { | 1481 | { |
1156 | struct sm501_devdata *sm = platform_get_drvdata(pdev); | 1482 | struct sm501_devdata *sm = platform_get_drvdata(pdev); |
1157 | 1483 | ||
1484 | sm501_set_power(sm, 1); | ||
1485 | |||
1158 | sm501_dump_regs(sm); | 1486 | sm501_dump_regs(sm); |
1159 | sm501_dump_gate(sm); | 1487 | sm501_dump_gate(sm); |
1160 | sm501_dump_clk(sm); | 1488 | sm501_dump_clk(sm); |
@@ -1229,6 +1557,7 @@ static struct sm501_platdata_fb sm501_fb_pdata = { | |||
1229 | static struct sm501_platdata sm501_pci_platdata = { | 1557 | static struct sm501_platdata sm501_pci_platdata = { |
1230 | .init = &sm501_pci_initdata, | 1558 | .init = &sm501_pci_initdata, |
1231 | .fb = &sm501_fb_pdata, | 1559 | .fb = &sm501_fb_pdata, |
1560 | .gpio_base = -1, | ||
1232 | }; | 1561 | }; |
1233 | 1562 | ||
1234 | static int sm501_pci_probe(struct pci_dev *dev, | 1563 | static int sm501_pci_probe(struct pci_dev *dev, |
@@ -1296,8 +1625,7 @@ static int sm501_pci_probe(struct pci_dev *dev, | |||
1296 | goto err3; | 1625 | goto err3; |
1297 | } | 1626 | } |
1298 | 1627 | ||
1299 | sm->regs = ioremap(pci_resource_start(dev, 1), | 1628 | sm->regs = pci_ioremap_bar(dev, 1); |
1300 | pci_resource_len(dev, 1)); | ||
1301 | 1629 | ||
1302 | if (sm->regs == NULL) { | 1630 | if (sm->regs == NULL) { |
1303 | dev_err(&dev->dev, "cannot remap registers\n"); | 1631 | dev_err(&dev->dev, "cannot remap registers\n"); |
@@ -1335,6 +1663,8 @@ static void sm501_dev_remove(struct sm501_devdata *sm) | |||
1335 | sm501_remove_sub(sm, smdev); | 1663 | sm501_remove_sub(sm, smdev); |
1336 | 1664 | ||
1337 | device_remove_file(sm->dev, &dev_attr_dbg_regs); | 1665 | device_remove_file(sm->dev, &dev_attr_dbg_regs); |
1666 | |||
1667 | sm501_gpio_remove(sm); | ||
1338 | } | 1668 | } |
1339 | 1669 | ||
1340 | static void sm501_pci_remove(struct pci_dev *dev) | 1670 | static void sm501_pci_remove(struct pci_dev *dev) |
@@ -1378,6 +1708,8 @@ static struct pci_driver sm501_pci_drv = { | |||
1378 | .remove = sm501_pci_remove, | 1708 | .remove = sm501_pci_remove, |
1379 | }; | 1709 | }; |
1380 | 1710 | ||
1711 | MODULE_ALIAS("platform:sm501"); | ||
1712 | |||
1381 | static struct platform_driver sm501_plat_drv = { | 1713 | static struct platform_driver sm501_plat_drv = { |
1382 | .driver = { | 1714 | .driver = { |
1383 | .name = "sm501", | 1715 | .name = "sm501", |
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c new file mode 100644 index 000000000000..9f7024c0f8ec --- /dev/null +++ b/drivers/mfd/t7l66xb.c | |||
@@ -0,0 +1,443 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Toshiba T7L66XB core mfd support | ||
4 | * | ||
5 | * Copyright (c) 2005, 2007, 2008 Ian Molton | ||
6 | * Copyright (c) 2008 Dmitry Baryshkov | ||
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 | * T7L66 features: | ||
13 | * | ||
14 | * Supported in this driver: | ||
15 | * SD/MMC | ||
16 | * SM/NAND flash controller | ||
17 | * | ||
18 | * As yet not supported | ||
19 | * GPIO interface (on NAND pins) | ||
20 | * Serial interface | ||
21 | * TFT 'interface converter' | ||
22 | * PCMCIA interface logic | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/io.h> | ||
29 | #include <linux/irq.h> | ||
30 | #include <linux/clk.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/mfd/core.h> | ||
33 | #include <linux/mfd/tmio.h> | ||
34 | #include <linux/mfd/t7l66xb.h> | ||
35 | |||
36 | enum { | ||
37 | T7L66XB_CELL_NAND, | ||
38 | T7L66XB_CELL_MMC, | ||
39 | }; | ||
40 | |||
41 | #define SCR_REVID 0x08 /* b Revision ID */ | ||
42 | #define SCR_IMR 0x42 /* b Interrupt Mask */ | ||
43 | #define SCR_DEV_CTL 0xe0 /* b Device control */ | ||
44 | #define SCR_ISR 0xe1 /* b Interrupt Status */ | ||
45 | #define SCR_GPO_OC 0xf0 /* b GPO output control */ | ||
46 | #define SCR_GPO_OS 0xf1 /* b GPO output enable */ | ||
47 | #define SCR_GPI_S 0xf2 /* w GPI status */ | ||
48 | #define SCR_APDC 0xf8 /* b Active pullup down ctrl */ | ||
49 | |||
50 | #define SCR_DEV_CTL_USB BIT(0) /* USB enable */ | ||
51 | #define SCR_DEV_CTL_MMC BIT(1) /* MMC enable */ | ||
52 | |||
53 | /*--------------------------------------------------------------------------*/ | ||
54 | |||
55 | struct t7l66xb { | ||
56 | void __iomem *scr; | ||
57 | /* Lock to protect registers requiring read/modify/write ops. */ | ||
58 | spinlock_t lock; | ||
59 | |||
60 | struct resource rscr; | ||
61 | struct clk *clk48m; | ||
62 | struct clk *clk32k; | ||
63 | int irq; | ||
64 | int irq_base; | ||
65 | }; | ||
66 | |||
67 | /*--------------------------------------------------------------------------*/ | ||
68 | |||
69 | static int t7l66xb_mmc_enable(struct platform_device *mmc) | ||
70 | { | ||
71 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
72 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
73 | unsigned long flags; | ||
74 | u8 dev_ctl; | ||
75 | |||
76 | clk_enable(t7l66xb->clk32k); | ||
77 | |||
78 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
79 | |||
80 | dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); | ||
81 | dev_ctl |= SCR_DEV_CTL_MMC; | ||
82 | tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); | ||
83 | |||
84 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int t7l66xb_mmc_disable(struct platform_device *mmc) | ||
90 | { | ||
91 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
92 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
93 | unsigned long flags; | ||
94 | u8 dev_ctl; | ||
95 | |||
96 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
97 | |||
98 | dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); | ||
99 | dev_ctl &= ~SCR_DEV_CTL_MMC; | ||
100 | tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); | ||
101 | |||
102 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
103 | |||
104 | clk_disable(t7l66xb->clk32k); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /*--------------------------------------------------------------------------*/ | ||
110 | |||
111 | const static struct resource t7l66xb_mmc_resources[] = { | ||
112 | { | ||
113 | .start = 0x800, | ||
114 | .end = 0x9ff, | ||
115 | .flags = IORESOURCE_MEM, | ||
116 | }, | ||
117 | { | ||
118 | .start = 0x200, | ||
119 | .end = 0x2ff, | ||
120 | .flags = IORESOURCE_MEM, | ||
121 | }, | ||
122 | { | ||
123 | .start = IRQ_T7L66XB_MMC, | ||
124 | .end = IRQ_T7L66XB_MMC, | ||
125 | .flags = IORESOURCE_IRQ, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | const static struct resource t7l66xb_nand_resources[] = { | ||
130 | { | ||
131 | .start = 0xc00, | ||
132 | .end = 0xc07, | ||
133 | .flags = IORESOURCE_MEM, | ||
134 | }, | ||
135 | { | ||
136 | .start = 0x0100, | ||
137 | .end = 0x01ff, | ||
138 | .flags = IORESOURCE_MEM, | ||
139 | }, | ||
140 | { | ||
141 | .start = IRQ_T7L66XB_NAND, | ||
142 | .end = IRQ_T7L66XB_NAND, | ||
143 | .flags = IORESOURCE_IRQ, | ||
144 | }, | ||
145 | }; | ||
146 | |||
147 | static struct mfd_cell t7l66xb_cells[] = { | ||
148 | [T7L66XB_CELL_MMC] = { | ||
149 | .name = "tmio-mmc", | ||
150 | .enable = t7l66xb_mmc_enable, | ||
151 | .disable = t7l66xb_mmc_disable, | ||
152 | .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), | ||
153 | .resources = t7l66xb_mmc_resources, | ||
154 | }, | ||
155 | [T7L66XB_CELL_NAND] = { | ||
156 | .name = "tmio-nand", | ||
157 | .num_resources = ARRAY_SIZE(t7l66xb_nand_resources), | ||
158 | .resources = t7l66xb_nand_resources, | ||
159 | }, | ||
160 | }; | ||
161 | |||
162 | /*--------------------------------------------------------------------------*/ | ||
163 | |||
164 | /* Handle the T7L66XB interrupt mux */ | ||
165 | static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) | ||
166 | { | ||
167 | struct t7l66xb *t7l66xb = get_irq_data(irq); | ||
168 | unsigned int isr; | ||
169 | unsigned int i, irq_base; | ||
170 | |||
171 | irq_base = t7l66xb->irq_base; | ||
172 | |||
173 | while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) & | ||
174 | ~tmio_ioread8(t7l66xb->scr + SCR_IMR))) | ||
175 | for (i = 0; i < T7L66XB_NR_IRQS; i++) | ||
176 | if (isr & (1 << i)) | ||
177 | generic_handle_irq(irq_base + i); | ||
178 | } | ||
179 | |||
180 | static void t7l66xb_irq_mask(unsigned int irq) | ||
181 | { | ||
182 | struct t7l66xb *t7l66xb = get_irq_chip_data(irq); | ||
183 | unsigned long flags; | ||
184 | u8 imr; | ||
185 | |||
186 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
187 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); | ||
188 | imr |= 1 << (irq - t7l66xb->irq_base); | ||
189 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); | ||
190 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
191 | } | ||
192 | |||
193 | static void t7l66xb_irq_unmask(unsigned int irq) | ||
194 | { | ||
195 | struct t7l66xb *t7l66xb = get_irq_chip_data(irq); | ||
196 | unsigned long flags; | ||
197 | u8 imr; | ||
198 | |||
199 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
200 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); | ||
201 | imr &= ~(1 << (irq - t7l66xb->irq_base)); | ||
202 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); | ||
203 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
204 | } | ||
205 | |||
206 | static struct irq_chip t7l66xb_chip = { | ||
207 | .name = "t7l66xb", | ||
208 | .ack = t7l66xb_irq_mask, | ||
209 | .mask = t7l66xb_irq_mask, | ||
210 | .unmask = t7l66xb_irq_unmask, | ||
211 | }; | ||
212 | |||
213 | /*--------------------------------------------------------------------------*/ | ||
214 | |||
215 | /* Install the IRQ handler */ | ||
216 | static void t7l66xb_attach_irq(struct platform_device *dev) | ||
217 | { | ||
218 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
219 | unsigned int irq, irq_base; | ||
220 | |||
221 | irq_base = t7l66xb->irq_base; | ||
222 | |||
223 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | ||
224 | set_irq_chip(irq, &t7l66xb_chip); | ||
225 | set_irq_chip_data(irq, t7l66xb); | ||
226 | set_irq_handler(irq, handle_level_irq); | ||
227 | #ifdef CONFIG_ARM | ||
228 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
229 | #endif | ||
230 | } | ||
231 | |||
232 | set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); | ||
233 | set_irq_data(t7l66xb->irq, t7l66xb); | ||
234 | set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); | ||
235 | } | ||
236 | |||
237 | static void t7l66xb_detach_irq(struct platform_device *dev) | ||
238 | { | ||
239 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
240 | unsigned int irq, irq_base; | ||
241 | |||
242 | irq_base = t7l66xb->irq_base; | ||
243 | |||
244 | set_irq_chained_handler(t7l66xb->irq, NULL); | ||
245 | set_irq_data(t7l66xb->irq, NULL); | ||
246 | |||
247 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | ||
248 | #ifdef CONFIG_ARM | ||
249 | set_irq_flags(irq, 0); | ||
250 | #endif | ||
251 | set_irq_chip(irq, NULL); | ||
252 | set_irq_chip_data(irq, NULL); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /*--------------------------------------------------------------------------*/ | ||
257 | |||
258 | #ifdef CONFIG_PM | ||
259 | static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) | ||
260 | { | ||
261 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
262 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
263 | |||
264 | if (pdata && pdata->suspend) | ||
265 | pdata->suspend(dev); | ||
266 | clk_disable(t7l66xb->clk48m); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int t7l66xb_resume(struct platform_device *dev) | ||
272 | { | ||
273 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
274 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
275 | |||
276 | clk_enable(t7l66xb->clk48m); | ||
277 | if (pdata && pdata->resume) | ||
278 | pdata->resume(dev); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | #else | ||
283 | #define t7l66xb_suspend NULL | ||
284 | #define t7l66xb_resume NULL | ||
285 | #endif | ||
286 | |||
287 | /*--------------------------------------------------------------------------*/ | ||
288 | |||
289 | static int t7l66xb_probe(struct platform_device *dev) | ||
290 | { | ||
291 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
292 | struct t7l66xb *t7l66xb; | ||
293 | struct resource *iomem, *rscr; | ||
294 | int ret; | ||
295 | |||
296 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
297 | if (!iomem) | ||
298 | return -EINVAL; | ||
299 | |||
300 | t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL); | ||
301 | if (!t7l66xb) | ||
302 | return -ENOMEM; | ||
303 | |||
304 | spin_lock_init(&t7l66xb->lock); | ||
305 | |||
306 | platform_set_drvdata(dev, t7l66xb); | ||
307 | |||
308 | ret = platform_get_irq(dev, 0); | ||
309 | if (ret >= 0) | ||
310 | t7l66xb->irq = ret; | ||
311 | else | ||
312 | goto err_noirq; | ||
313 | |||
314 | t7l66xb->irq_base = pdata->irq_base; | ||
315 | |||
316 | t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K"); | ||
317 | if (IS_ERR(t7l66xb->clk32k)) { | ||
318 | ret = PTR_ERR(t7l66xb->clk32k); | ||
319 | goto err_clk32k_get; | ||
320 | } | ||
321 | |||
322 | t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M"); | ||
323 | if (IS_ERR(t7l66xb->clk48m)) { | ||
324 | ret = PTR_ERR(t7l66xb->clk48m); | ||
325 | clk_put(t7l66xb->clk32k); | ||
326 | goto err_clk48m_get; | ||
327 | } | ||
328 | |||
329 | rscr = &t7l66xb->rscr; | ||
330 | rscr->name = "t7l66xb-core"; | ||
331 | rscr->start = iomem->start; | ||
332 | rscr->end = iomem->start + 0xff; | ||
333 | rscr->flags = IORESOURCE_MEM; | ||
334 | |||
335 | ret = request_resource(iomem, rscr); | ||
336 | if (ret) | ||
337 | goto err_request_scr; | ||
338 | |||
339 | t7l66xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); | ||
340 | if (!t7l66xb->scr) { | ||
341 | ret = -ENOMEM; | ||
342 | goto err_ioremap; | ||
343 | } | ||
344 | |||
345 | clk_enable(t7l66xb->clk48m); | ||
346 | |||
347 | if (pdata && pdata->enable) | ||
348 | pdata->enable(dev); | ||
349 | |||
350 | /* Mask all interrupts */ | ||
351 | tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR); | ||
352 | |||
353 | printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n", | ||
354 | dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID), | ||
355 | (unsigned long)iomem->start, t7l66xb->irq); | ||
356 | |||
357 | t7l66xb_attach_irq(dev); | ||
358 | |||
359 | t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; | ||
360 | t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = | ||
361 | &t7l66xb_cells[T7L66XB_CELL_NAND]; | ||
362 | t7l66xb_cells[T7L66XB_CELL_NAND].data_size = | ||
363 | sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); | ||
364 | |||
365 | t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = | ||
366 | &t7l66xb_cells[T7L66XB_CELL_MMC]; | ||
367 | t7l66xb_cells[T7L66XB_CELL_MMC].data_size = | ||
368 | sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); | ||
369 | |||
370 | ret = mfd_add_devices(&dev->dev, dev->id, | ||
371 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), | ||
372 | iomem, t7l66xb->irq_base); | ||
373 | |||
374 | if (!ret) | ||
375 | return 0; | ||
376 | |||
377 | t7l66xb_detach_irq(dev); | ||
378 | iounmap(t7l66xb->scr); | ||
379 | err_ioremap: | ||
380 | release_resource(&t7l66xb->rscr); | ||
381 | err_request_scr: | ||
382 | kfree(t7l66xb); | ||
383 | clk_put(t7l66xb->clk48m); | ||
384 | err_clk48m_get: | ||
385 | clk_put(t7l66xb->clk32k); | ||
386 | err_clk32k_get: | ||
387 | err_noirq: | ||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | static int t7l66xb_remove(struct platform_device *dev) | ||
392 | { | ||
393 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
394 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
395 | int ret; | ||
396 | |||
397 | ret = pdata->disable(dev); | ||
398 | clk_disable(t7l66xb->clk48m); | ||
399 | clk_put(t7l66xb->clk48m); | ||
400 | t7l66xb_detach_irq(dev); | ||
401 | iounmap(t7l66xb->scr); | ||
402 | release_resource(&t7l66xb->rscr); | ||
403 | mfd_remove_devices(&dev->dev); | ||
404 | platform_set_drvdata(dev, NULL); | ||
405 | kfree(t7l66xb); | ||
406 | |||
407 | return ret; | ||
408 | |||
409 | } | ||
410 | |||
411 | static struct platform_driver t7l66xb_platform_driver = { | ||
412 | .driver = { | ||
413 | .name = "t7l66xb", | ||
414 | .owner = THIS_MODULE, | ||
415 | }, | ||
416 | .suspend = t7l66xb_suspend, | ||
417 | .resume = t7l66xb_resume, | ||
418 | .probe = t7l66xb_probe, | ||
419 | .remove = t7l66xb_remove, | ||
420 | }; | ||
421 | |||
422 | /*--------------------------------------------------------------------------*/ | ||
423 | |||
424 | static int __init t7l66xb_init(void) | ||
425 | { | ||
426 | int retval = 0; | ||
427 | |||
428 | retval = platform_driver_register(&t7l66xb_platform_driver); | ||
429 | return retval; | ||
430 | } | ||
431 | |||
432 | static void __exit t7l66xb_exit(void) | ||
433 | { | ||
434 | platform_driver_unregister(&t7l66xb_platform_driver); | ||
435 | } | ||
436 | |||
437 | module_init(t7l66xb_init); | ||
438 | module_exit(t7l66xb_exit); | ||
439 | |||
440 | MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); | ||
441 | MODULE_LICENSE("GPL v2"); | ||
442 | MODULE_AUTHOR("Ian Molton"); | ||
443 | MODULE_ALIAS("platform:t7l66xb"); | ||
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c new file mode 100644 index 000000000000..43222c12fec1 --- /dev/null +++ b/drivers/mfd/tc6387xb.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Toshiba TC6387XB support | ||
3 | * Copyright (c) 2005 Ian Molton | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This file contains TC6387XB base support. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/mfd/core.h> | ||
18 | #include <linux/mfd/tmio.h> | ||
19 | #include <linux/mfd/tc6387xb.h> | ||
20 | |||
21 | enum { | ||
22 | TC6387XB_CELL_MMC, | ||
23 | }; | ||
24 | |||
25 | #ifdef CONFIG_PM | ||
26 | static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) | ||
27 | { | ||
28 | struct clk *clk32k = platform_get_drvdata(dev); | ||
29 | struct tc6387xb_platform_data *pdata = dev->dev.platform_data; | ||
30 | |||
31 | if (pdata && pdata->suspend) | ||
32 | pdata->suspend(dev); | ||
33 | clk_disable(clk32k); | ||
34 | |||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static int tc6387xb_resume(struct platform_device *dev) | ||
39 | { | ||
40 | struct clk *clk32k = platform_get_drvdata(dev); | ||
41 | struct tc6387xb_platform_data *pdata = dev->dev.platform_data; | ||
42 | |||
43 | clk_enable(clk32k); | ||
44 | if (pdata && pdata->resume) | ||
45 | pdata->resume(dev); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | #else | ||
50 | #define tc6387xb_suspend NULL | ||
51 | #define tc6387xb_resume NULL | ||
52 | #endif | ||
53 | |||
54 | /*--------------------------------------------------------------------------*/ | ||
55 | |||
56 | static int tc6387xb_mmc_enable(struct platform_device *mmc) | ||
57 | { | ||
58 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
59 | struct clk *clk32k = platform_get_drvdata(dev); | ||
60 | |||
61 | clk_enable(clk32k); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int tc6387xb_mmc_disable(struct platform_device *mmc) | ||
67 | { | ||
68 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
69 | struct clk *clk32k = platform_get_drvdata(dev); | ||
70 | |||
71 | clk_disable(clk32k); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | /*--------------------------------------------------------------------------*/ | ||
77 | |||
78 | static struct resource tc6387xb_mmc_resources[] = { | ||
79 | { | ||
80 | .start = 0x800, | ||
81 | .end = 0x9ff, | ||
82 | .flags = IORESOURCE_MEM, | ||
83 | }, | ||
84 | { | ||
85 | .start = 0x200, | ||
86 | .end = 0x2ff, | ||
87 | .flags = IORESOURCE_MEM, | ||
88 | }, | ||
89 | { | ||
90 | .start = 0, | ||
91 | .end = 0, | ||
92 | .flags = IORESOURCE_IRQ, | ||
93 | }, | ||
94 | }; | ||
95 | |||
96 | static struct mfd_cell tc6387xb_cells[] = { | ||
97 | [TC6387XB_CELL_MMC] = { | ||
98 | .name = "tmio-mmc", | ||
99 | .enable = tc6387xb_mmc_enable, | ||
100 | .disable = tc6387xb_mmc_disable, | ||
101 | .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), | ||
102 | .resources = tc6387xb_mmc_resources, | ||
103 | }, | ||
104 | }; | ||
105 | |||
106 | static int tc6387xb_probe(struct platform_device *dev) | ||
107 | { | ||
108 | struct tc6387xb_platform_data *pdata = dev->dev.platform_data; | ||
109 | struct resource *iomem; | ||
110 | struct clk *clk32k; | ||
111 | int irq, ret; | ||
112 | |||
113 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
114 | if (!iomem) { | ||
115 | return -EINVAL; | ||
116 | } | ||
117 | |||
118 | ret = platform_get_irq(dev, 0); | ||
119 | if (ret >= 0) | ||
120 | irq = ret; | ||
121 | else | ||
122 | goto err_resource; | ||
123 | |||
124 | clk32k = clk_get(&dev->dev, "CLK_CK32K"); | ||
125 | if (IS_ERR(clk32k)) { | ||
126 | ret = PTR_ERR(clk32k); | ||
127 | goto err_resource; | ||
128 | } | ||
129 | platform_set_drvdata(dev, clk32k); | ||
130 | |||
131 | if (pdata && pdata->enable) | ||
132 | pdata->enable(dev); | ||
133 | |||
134 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); | ||
135 | |||
136 | tc6387xb_cells[TC6387XB_CELL_MMC].platform_data = | ||
137 | &tc6387xb_cells[TC6387XB_CELL_MMC]; | ||
138 | tc6387xb_cells[TC6387XB_CELL_MMC].data_size = | ||
139 | sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]); | ||
140 | |||
141 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, | ||
142 | ARRAY_SIZE(tc6387xb_cells), iomem, irq); | ||
143 | |||
144 | if (!ret) | ||
145 | return 0; | ||
146 | |||
147 | clk_put(clk32k); | ||
148 | err_resource: | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | static int tc6387xb_remove(struct platform_device *dev) | ||
153 | { | ||
154 | struct clk *clk32k = platform_get_drvdata(dev); | ||
155 | |||
156 | mfd_remove_devices(&dev->dev); | ||
157 | clk_disable(clk32k); | ||
158 | clk_put(clk32k); | ||
159 | platform_set_drvdata(dev, NULL); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | |||
165 | static struct platform_driver tc6387xb_platform_driver = { | ||
166 | .driver = { | ||
167 | .name = "tc6387xb", | ||
168 | }, | ||
169 | .probe = tc6387xb_probe, | ||
170 | .remove = tc6387xb_remove, | ||
171 | .suspend = tc6387xb_suspend, | ||
172 | .resume = tc6387xb_resume, | ||
173 | }; | ||
174 | |||
175 | |||
176 | static int __init tc6387xb_init(void) | ||
177 | { | ||
178 | return platform_driver_register(&tc6387xb_platform_driver); | ||
179 | } | ||
180 | |||
181 | static void __exit tc6387xb_exit(void) | ||
182 | { | ||
183 | platform_driver_unregister(&tc6387xb_platform_driver); | ||
184 | } | ||
185 | |||
186 | module_init(tc6387xb_init); | ||
187 | module_exit(tc6387xb_exit); | ||
188 | |||
189 | MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); | ||
190 | MODULE_LICENSE("GPL v2"); | ||
191 | MODULE_AUTHOR("Ian Molton"); | ||
192 | MODULE_ALIAS("platform:tc6387xb"); | ||
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c new file mode 100644 index 000000000000..f856e9463a9f --- /dev/null +++ b/drivers/mfd/tc6393xb.c | |||
@@ -0,0 +1,833 @@ | |||
1 | /* | ||
2 | * Toshiba TC6393XB SoC support | ||
3 | * | ||
4 | * Copyright(c) 2005-2006 Chris Humbert | ||
5 | * Copyright(c) 2005 Dirk Opfer | ||
6 | * Copyright(c) 2005 Ian Molton <spyro@f2s.com> | ||
7 | * Copyright(c) 2007 Dmitry Baryshkov | ||
8 | * | ||
9 | * Based on code written by Sharp/Lineo for 2.4 kernels | ||
10 | * Based on locomo.c | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/mfd/core.h> | ||
25 | #include <linux/mfd/tmio.h> | ||
26 | #include <linux/mfd/tc6393xb.h> | ||
27 | #include <linux/gpio.h> | ||
28 | |||
29 | #define SCR_REVID 0x08 /* b Revision ID */ | ||
30 | #define SCR_ISR 0x50 /* b Interrupt Status */ | ||
31 | #define SCR_IMR 0x52 /* b Interrupt Mask */ | ||
32 | #define SCR_IRR 0x54 /* b Interrupt Routing */ | ||
33 | #define SCR_GPER 0x60 /* w GP Enable */ | ||
34 | #define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */ | ||
35 | #define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */ | ||
36 | #define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */ | ||
37 | #define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */ | ||
38 | #define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */ | ||
39 | #define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */ | ||
40 | #define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */ | ||
41 | #define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */ | ||
42 | #define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */ | ||
43 | #define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */ | ||
44 | #define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */ | ||
45 | #define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */ | ||
46 | #define SCR_CCR 0x98 /* w Clock Control */ | ||
47 | #define SCR_PLL2CR 0x9a /* w PLL2 Control */ | ||
48 | #define SCR_PLL1CR 0x9c /* l PLL1 Control */ | ||
49 | #define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */ | ||
50 | #define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */ | ||
51 | #define SCR_FER 0xe0 /* b Function Enable */ | ||
52 | #define SCR_MCR 0xe4 /* w Mode Control */ | ||
53 | #define SCR_CONFIG 0xfc /* b Configuration Control */ | ||
54 | #define SCR_DEBUG 0xff /* b Debug */ | ||
55 | |||
56 | #define SCR_CCR_CK32K BIT(0) | ||
57 | #define SCR_CCR_USBCK BIT(1) | ||
58 | #define SCR_CCR_UNK1 BIT(4) | ||
59 | #define SCR_CCR_MCLK_MASK (7 << 8) | ||
60 | #define SCR_CCR_MCLK_OFF (0 << 8) | ||
61 | #define SCR_CCR_MCLK_12 (1 << 8) | ||
62 | #define SCR_CCR_MCLK_24 (2 << 8) | ||
63 | #define SCR_CCR_MCLK_48 (3 << 8) | ||
64 | #define SCR_CCR_HCLK_MASK (3 << 12) | ||
65 | #define SCR_CCR_HCLK_24 (0 << 12) | ||
66 | #define SCR_CCR_HCLK_48 (1 << 12) | ||
67 | |||
68 | #define SCR_FER_USBEN BIT(0) /* USB host enable */ | ||
69 | #define SCR_FER_LCDCVEN BIT(1) /* polysilicon TFT enable */ | ||
70 | #define SCR_FER_SLCDEN BIT(2) /* SLCD enable */ | ||
71 | |||
72 | #define SCR_MCR_RDY_MASK (3 << 0) | ||
73 | #define SCR_MCR_RDY_OPENDRAIN (0 << 0) | ||
74 | #define SCR_MCR_RDY_TRISTATE (1 << 0) | ||
75 | #define SCR_MCR_RDY_PUSHPULL (2 << 0) | ||
76 | #define SCR_MCR_RDY_UNK BIT(2) | ||
77 | #define SCR_MCR_RDY_EN BIT(3) | ||
78 | #define SCR_MCR_INT_MASK (3 << 4) | ||
79 | #define SCR_MCR_INT_OPENDRAIN (0 << 4) | ||
80 | #define SCR_MCR_INT_TRISTATE (1 << 4) | ||
81 | #define SCR_MCR_INT_PUSHPULL (2 << 4) | ||
82 | #define SCR_MCR_INT_UNK BIT(6) | ||
83 | #define SCR_MCR_INT_EN BIT(7) | ||
84 | /* bits 8 - 16 are unknown */ | ||
85 | |||
86 | #define TC_GPIO_BIT(i) (1 << (i & 0x7)) | ||
87 | |||
88 | /*--------------------------------------------------------------------------*/ | ||
89 | |||
90 | struct tc6393xb { | ||
91 | void __iomem *scr; | ||
92 | |||
93 | struct gpio_chip gpio; | ||
94 | |||
95 | struct clk *clk; /* 3,6 Mhz */ | ||
96 | |||
97 | spinlock_t lock; /* protects RMW cycles */ | ||
98 | |||
99 | struct { | ||
100 | u8 fer; | ||
101 | u16 ccr; | ||
102 | u8 gpi_bcr[3]; | ||
103 | u8 gpo_dsr[3]; | ||
104 | u8 gpo_doecr[3]; | ||
105 | } suspend_state; | ||
106 | |||
107 | struct resource rscr; | ||
108 | struct resource *iomem; | ||
109 | int irq; | ||
110 | int irq_base; | ||
111 | }; | ||
112 | |||
113 | enum { | ||
114 | TC6393XB_CELL_NAND, | ||
115 | TC6393XB_CELL_MMC, | ||
116 | TC6393XB_CELL_OHCI, | ||
117 | TC6393XB_CELL_FB, | ||
118 | }; | ||
119 | |||
120 | /*--------------------------------------------------------------------------*/ | ||
121 | |||
122 | static int tc6393xb_nand_enable(struct platform_device *nand) | ||
123 | { | ||
124 | struct platform_device *dev = to_platform_device(nand->dev.parent); | ||
125 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
126 | unsigned long flags; | ||
127 | |||
128 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
129 | |||
130 | /* SMD buffer on */ | ||
131 | dev_dbg(&dev->dev, "SMD buffer on\n"); | ||
132 | tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); | ||
133 | |||
134 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static struct resource __devinitdata tc6393xb_nand_resources[] = { | ||
140 | { | ||
141 | .start = 0x1000, | ||
142 | .end = 0x1007, | ||
143 | .flags = IORESOURCE_MEM, | ||
144 | }, | ||
145 | { | ||
146 | .start = 0x0100, | ||
147 | .end = 0x01ff, | ||
148 | .flags = IORESOURCE_MEM, | ||
149 | }, | ||
150 | { | ||
151 | .start = IRQ_TC6393_NAND, | ||
152 | .end = IRQ_TC6393_NAND, | ||
153 | .flags = IORESOURCE_IRQ, | ||
154 | }, | ||
155 | }; | ||
156 | |||
157 | static struct resource __devinitdata tc6393xb_mmc_resources[] = { | ||
158 | { | ||
159 | .start = 0x800, | ||
160 | .end = 0x9ff, | ||
161 | .flags = IORESOURCE_MEM, | ||
162 | }, | ||
163 | { | ||
164 | .start = 0x200, | ||
165 | .end = 0x2ff, | ||
166 | .flags = IORESOURCE_MEM, | ||
167 | }, | ||
168 | { | ||
169 | .start = IRQ_TC6393_MMC, | ||
170 | .end = IRQ_TC6393_MMC, | ||
171 | .flags = IORESOURCE_IRQ, | ||
172 | }, | ||
173 | }; | ||
174 | |||
175 | const static struct resource tc6393xb_ohci_resources[] = { | ||
176 | { | ||
177 | .start = 0x3000, | ||
178 | .end = 0x31ff, | ||
179 | .flags = IORESOURCE_MEM, | ||
180 | }, | ||
181 | { | ||
182 | .start = 0x0300, | ||
183 | .end = 0x03ff, | ||
184 | .flags = IORESOURCE_MEM, | ||
185 | }, | ||
186 | { | ||
187 | .start = 0x010000, | ||
188 | .end = 0x017fff, | ||
189 | .flags = IORESOURCE_MEM, | ||
190 | }, | ||
191 | { | ||
192 | .start = 0x018000, | ||
193 | .end = 0x01ffff, | ||
194 | .flags = IORESOURCE_MEM, | ||
195 | }, | ||
196 | { | ||
197 | .start = IRQ_TC6393_OHCI, | ||
198 | .end = IRQ_TC6393_OHCI, | ||
199 | .flags = IORESOURCE_IRQ, | ||
200 | }, | ||
201 | }; | ||
202 | |||
203 | static struct resource __devinitdata tc6393xb_fb_resources[] = { | ||
204 | { | ||
205 | .start = 0x5000, | ||
206 | .end = 0x51ff, | ||
207 | .flags = IORESOURCE_MEM, | ||
208 | }, | ||
209 | { | ||
210 | .start = 0x0500, | ||
211 | .end = 0x05ff, | ||
212 | .flags = IORESOURCE_MEM, | ||
213 | }, | ||
214 | { | ||
215 | .start = 0x100000, | ||
216 | .end = 0x1fffff, | ||
217 | .flags = IORESOURCE_MEM, | ||
218 | }, | ||
219 | { | ||
220 | .start = IRQ_TC6393_FB, | ||
221 | .end = IRQ_TC6393_FB, | ||
222 | .flags = IORESOURCE_IRQ, | ||
223 | }, | ||
224 | }; | ||
225 | |||
226 | static int tc6393xb_ohci_enable(struct platform_device *dev) | ||
227 | { | ||
228 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
229 | unsigned long flags; | ||
230 | u16 ccr; | ||
231 | u8 fer; | ||
232 | |||
233 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
234 | |||
235 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
236 | ccr |= SCR_CCR_USBCK; | ||
237 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
238 | |||
239 | fer = tmio_ioread8(tc6393xb->scr + SCR_FER); | ||
240 | fer |= SCR_FER_USBEN; | ||
241 | tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); | ||
242 | |||
243 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int tc6393xb_ohci_disable(struct platform_device *dev) | ||
249 | { | ||
250 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
251 | unsigned long flags; | ||
252 | u16 ccr; | ||
253 | u8 fer; | ||
254 | |||
255 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
256 | |||
257 | fer = tmio_ioread8(tc6393xb->scr + SCR_FER); | ||
258 | fer &= ~SCR_FER_USBEN; | ||
259 | tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); | ||
260 | |||
261 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
262 | ccr &= ~SCR_CCR_USBCK; | ||
263 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
264 | |||
265 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int tc6393xb_fb_enable(struct platform_device *dev) | ||
271 | { | ||
272 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
273 | unsigned long flags; | ||
274 | u16 ccr; | ||
275 | |||
276 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
277 | |||
278 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
279 | ccr &= ~SCR_CCR_MCLK_MASK; | ||
280 | ccr |= SCR_CCR_MCLK_48; | ||
281 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
282 | |||
283 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int tc6393xb_fb_disable(struct platform_device *dev) | ||
289 | { | ||
290 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
291 | unsigned long flags; | ||
292 | u16 ccr; | ||
293 | |||
294 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
295 | |||
296 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
297 | ccr &= ~SCR_CCR_MCLK_MASK; | ||
298 | ccr |= SCR_CCR_MCLK_OFF; | ||
299 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
300 | |||
301 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | int tc6393xb_lcd_set_power(struct platform_device *fb, bool on) | ||
307 | { | ||
308 | struct platform_device *dev = to_platform_device(fb->dev.parent); | ||
309 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
310 | u8 fer; | ||
311 | unsigned long flags; | ||
312 | |||
313 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
314 | |||
315 | fer = ioread8(tc6393xb->scr + SCR_FER); | ||
316 | if (on) | ||
317 | fer |= SCR_FER_SLCDEN; | ||
318 | else | ||
319 | fer &= ~SCR_FER_SLCDEN; | ||
320 | iowrite8(fer, tc6393xb->scr + SCR_FER); | ||
321 | |||
322 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | EXPORT_SYMBOL(tc6393xb_lcd_set_power); | ||
327 | |||
328 | int tc6393xb_lcd_mode(struct platform_device *fb, | ||
329 | const struct fb_videomode *mode) { | ||
330 | struct platform_device *dev = to_platform_device(fb->dev.parent); | ||
331 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
332 | unsigned long flags; | ||
333 | |||
334 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
335 | |||
336 | iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0); | ||
337 | iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2); | ||
338 | |||
339 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | EXPORT_SYMBOL(tc6393xb_lcd_mode); | ||
344 | |||
345 | static struct mfd_cell __devinitdata tc6393xb_cells[] = { | ||
346 | [TC6393XB_CELL_NAND] = { | ||
347 | .name = "tmio-nand", | ||
348 | .enable = tc6393xb_nand_enable, | ||
349 | .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), | ||
350 | .resources = tc6393xb_nand_resources, | ||
351 | }, | ||
352 | [TC6393XB_CELL_MMC] = { | ||
353 | .name = "tmio-mmc", | ||
354 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), | ||
355 | .resources = tc6393xb_mmc_resources, | ||
356 | }, | ||
357 | [TC6393XB_CELL_OHCI] = { | ||
358 | .name = "tmio-ohci", | ||
359 | .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources), | ||
360 | .resources = tc6393xb_ohci_resources, | ||
361 | .enable = tc6393xb_ohci_enable, | ||
362 | .suspend = tc6393xb_ohci_disable, | ||
363 | .resume = tc6393xb_ohci_enable, | ||
364 | .disable = tc6393xb_ohci_disable, | ||
365 | }, | ||
366 | [TC6393XB_CELL_FB] = { | ||
367 | .name = "tmio-fb", | ||
368 | .num_resources = ARRAY_SIZE(tc6393xb_fb_resources), | ||
369 | .resources = tc6393xb_fb_resources, | ||
370 | .enable = tc6393xb_fb_enable, | ||
371 | .suspend = tc6393xb_fb_disable, | ||
372 | .resume = tc6393xb_fb_enable, | ||
373 | .disable = tc6393xb_fb_disable, | ||
374 | }, | ||
375 | }; | ||
376 | |||
377 | /*--------------------------------------------------------------------------*/ | ||
378 | |||
379 | static int tc6393xb_gpio_get(struct gpio_chip *chip, | ||
380 | unsigned offset) | ||
381 | { | ||
382 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); | ||
383 | |||
384 | /* XXX: does dsr also represent inputs? */ | ||
385 | return tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) | ||
386 | & TC_GPIO_BIT(offset); | ||
387 | } | ||
388 | |||
389 | static void __tc6393xb_gpio_set(struct gpio_chip *chip, | ||
390 | unsigned offset, int value) | ||
391 | { | ||
392 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); | ||
393 | u8 dsr; | ||
394 | |||
395 | dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); | ||
396 | if (value) | ||
397 | dsr |= TC_GPIO_BIT(offset); | ||
398 | else | ||
399 | dsr &= ~TC_GPIO_BIT(offset); | ||
400 | |||
401 | tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); | ||
402 | } | ||
403 | |||
404 | static void tc6393xb_gpio_set(struct gpio_chip *chip, | ||
405 | unsigned offset, int value) | ||
406 | { | ||
407 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); | ||
408 | unsigned long flags; | ||
409 | |||
410 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
411 | |||
412 | __tc6393xb_gpio_set(chip, offset, value); | ||
413 | |||
414 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
415 | } | ||
416 | |||
417 | static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, | ||
418 | unsigned offset) | ||
419 | { | ||
420 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); | ||
421 | unsigned long flags; | ||
422 | u8 doecr; | ||
423 | |||
424 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
425 | |||
426 | doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | ||
427 | doecr &= ~TC_GPIO_BIT(offset); | ||
428 | tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | ||
429 | |||
430 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, | ||
436 | unsigned offset, int value) | ||
437 | { | ||
438 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); | ||
439 | unsigned long flags; | ||
440 | u8 doecr; | ||
441 | |||
442 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
443 | |||
444 | __tc6393xb_gpio_set(chip, offset, value); | ||
445 | |||
446 | doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | ||
447 | doecr |= TC_GPIO_BIT(offset); | ||
448 | tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | ||
449 | |||
450 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) | ||
456 | { | ||
457 | tc6393xb->gpio.label = "tc6393xb"; | ||
458 | tc6393xb->gpio.base = gpio_base; | ||
459 | tc6393xb->gpio.ngpio = 16; | ||
460 | tc6393xb->gpio.set = tc6393xb_gpio_set; | ||
461 | tc6393xb->gpio.get = tc6393xb_gpio_get; | ||
462 | tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input; | ||
463 | tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output; | ||
464 | |||
465 | return gpiochip_add(&tc6393xb->gpio); | ||
466 | } | ||
467 | |||
468 | /*--------------------------------------------------------------------------*/ | ||
469 | |||
470 | static void | ||
471 | tc6393xb_irq(unsigned int irq, struct irq_desc *desc) | ||
472 | { | ||
473 | struct tc6393xb *tc6393xb = get_irq_data(irq); | ||
474 | unsigned int isr; | ||
475 | unsigned int i, irq_base; | ||
476 | |||
477 | irq_base = tc6393xb->irq_base; | ||
478 | |||
479 | while ((isr = tmio_ioread8(tc6393xb->scr + SCR_ISR) & | ||
480 | ~tmio_ioread8(tc6393xb->scr + SCR_IMR))) | ||
481 | for (i = 0; i < TC6393XB_NR_IRQS; i++) { | ||
482 | if (isr & (1 << i)) | ||
483 | generic_handle_irq(irq_base + i); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | static void tc6393xb_irq_ack(unsigned int irq) | ||
488 | { | ||
489 | } | ||
490 | |||
491 | static void tc6393xb_irq_mask(unsigned int irq) | ||
492 | { | ||
493 | struct tc6393xb *tc6393xb = get_irq_chip_data(irq); | ||
494 | unsigned long flags; | ||
495 | u8 imr; | ||
496 | |||
497 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
498 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); | ||
499 | imr |= 1 << (irq - tc6393xb->irq_base); | ||
500 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); | ||
501 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
502 | } | ||
503 | |||
504 | static void tc6393xb_irq_unmask(unsigned int irq) | ||
505 | { | ||
506 | struct tc6393xb *tc6393xb = get_irq_chip_data(irq); | ||
507 | unsigned long flags; | ||
508 | u8 imr; | ||
509 | |||
510 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
511 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); | ||
512 | imr &= ~(1 << (irq - tc6393xb->irq_base)); | ||
513 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); | ||
514 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
515 | } | ||
516 | |||
517 | static struct irq_chip tc6393xb_chip = { | ||
518 | .name = "tc6393xb", | ||
519 | .ack = tc6393xb_irq_ack, | ||
520 | .mask = tc6393xb_irq_mask, | ||
521 | .unmask = tc6393xb_irq_unmask, | ||
522 | }; | ||
523 | |||
524 | static void tc6393xb_attach_irq(struct platform_device *dev) | ||
525 | { | ||
526 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
527 | unsigned int irq, irq_base; | ||
528 | |||
529 | irq_base = tc6393xb->irq_base; | ||
530 | |||
531 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { | ||
532 | set_irq_chip(irq, &tc6393xb_chip); | ||
533 | set_irq_chip_data(irq, tc6393xb); | ||
534 | set_irq_handler(irq, handle_edge_irq); | ||
535 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
536 | } | ||
537 | |||
538 | set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); | ||
539 | set_irq_data(tc6393xb->irq, tc6393xb); | ||
540 | set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq); | ||
541 | } | ||
542 | |||
543 | static void tc6393xb_detach_irq(struct platform_device *dev) | ||
544 | { | ||
545 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
546 | unsigned int irq, irq_base; | ||
547 | |||
548 | set_irq_chained_handler(tc6393xb->irq, NULL); | ||
549 | set_irq_data(tc6393xb->irq, NULL); | ||
550 | |||
551 | irq_base = tc6393xb->irq_base; | ||
552 | |||
553 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { | ||
554 | set_irq_flags(irq, 0); | ||
555 | set_irq_chip(irq, NULL); | ||
556 | set_irq_chip_data(irq, NULL); | ||
557 | } | ||
558 | } | ||
559 | |||
560 | /*--------------------------------------------------------------------------*/ | ||
561 | |||
562 | static int __devinit tc6393xb_probe(struct platform_device *dev) | ||
563 | { | ||
564 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | ||
565 | struct tc6393xb *tc6393xb; | ||
566 | struct resource *iomem, *rscr; | ||
567 | int ret, temp; | ||
568 | |||
569 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
570 | if (!iomem) | ||
571 | return -EINVAL; | ||
572 | |||
573 | tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); | ||
574 | if (!tc6393xb) { | ||
575 | ret = -ENOMEM; | ||
576 | goto err_kzalloc; | ||
577 | } | ||
578 | |||
579 | spin_lock_init(&tc6393xb->lock); | ||
580 | |||
581 | platform_set_drvdata(dev, tc6393xb); | ||
582 | |||
583 | ret = platform_get_irq(dev, 0); | ||
584 | if (ret >= 0) | ||
585 | tc6393xb->irq = ret; | ||
586 | else | ||
587 | goto err_noirq; | ||
588 | |||
589 | tc6393xb->iomem = iomem; | ||
590 | tc6393xb->irq_base = tcpd->irq_base; | ||
591 | |||
592 | tc6393xb->clk = clk_get(&dev->dev, "CLK_CK3P6MI"); | ||
593 | if (IS_ERR(tc6393xb->clk)) { | ||
594 | ret = PTR_ERR(tc6393xb->clk); | ||
595 | goto err_clk_get; | ||
596 | } | ||
597 | |||
598 | rscr = &tc6393xb->rscr; | ||
599 | rscr->name = "tc6393xb-core"; | ||
600 | rscr->start = iomem->start; | ||
601 | rscr->end = iomem->start + 0xff; | ||
602 | rscr->flags = IORESOURCE_MEM; | ||
603 | |||
604 | ret = request_resource(iomem, rscr); | ||
605 | if (ret) | ||
606 | goto err_request_scr; | ||
607 | |||
608 | tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); | ||
609 | if (!tc6393xb->scr) { | ||
610 | ret = -ENOMEM; | ||
611 | goto err_ioremap; | ||
612 | } | ||
613 | |||
614 | ret = clk_enable(tc6393xb->clk); | ||
615 | if (ret) | ||
616 | goto err_clk_enable; | ||
617 | |||
618 | ret = tcpd->enable(dev); | ||
619 | if (ret) | ||
620 | goto err_enable; | ||
621 | |||
622 | iowrite8(0, tc6393xb->scr + SCR_FER); | ||
623 | iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); | ||
624 | iowrite16(SCR_CCR_UNK1 | SCR_CCR_HCLK_48, | ||
625 | tc6393xb->scr + SCR_CCR); | ||
626 | iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | | ||
627 | SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | | ||
628 | BIT(15), tc6393xb->scr + SCR_MCR); | ||
629 | iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); | ||
630 | iowrite8(0, tc6393xb->scr + SCR_IRR); | ||
631 | iowrite8(0xbf, tc6393xb->scr + SCR_IMR); | ||
632 | |||
633 | printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", | ||
634 | tmio_ioread8(tc6393xb->scr + SCR_REVID), | ||
635 | (unsigned long) iomem->start, tc6393xb->irq); | ||
636 | |||
637 | tc6393xb->gpio.base = -1; | ||
638 | |||
639 | if (tcpd->gpio_base >= 0) { | ||
640 | ret = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); | ||
641 | if (ret) | ||
642 | goto err_gpio_add; | ||
643 | } | ||
644 | |||
645 | tc6393xb_attach_irq(dev); | ||
646 | |||
647 | if (tcpd->setup) { | ||
648 | ret = tcpd->setup(dev); | ||
649 | if (ret) | ||
650 | goto err_setup; | ||
651 | } | ||
652 | |||
653 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; | ||
654 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = | ||
655 | &tc6393xb_cells[TC6393XB_CELL_NAND]; | ||
656 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = | ||
657 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); | ||
658 | |||
659 | tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = | ||
660 | &tc6393xb_cells[TC6393XB_CELL_MMC]; | ||
661 | tc6393xb_cells[TC6393XB_CELL_MMC].data_size = | ||
662 | sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); | ||
663 | |||
664 | tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data = | ||
665 | &tc6393xb_cells[TC6393XB_CELL_OHCI]; | ||
666 | tc6393xb_cells[TC6393XB_CELL_OHCI].data_size = | ||
667 | sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]); | ||
668 | |||
669 | tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data; | ||
670 | tc6393xb_cells[TC6393XB_CELL_FB].platform_data = | ||
671 | &tc6393xb_cells[TC6393XB_CELL_FB]; | ||
672 | tc6393xb_cells[TC6393XB_CELL_FB].data_size = | ||
673 | sizeof(tc6393xb_cells[TC6393XB_CELL_FB]); | ||
674 | |||
675 | ret = mfd_add_devices(&dev->dev, dev->id, | ||
676 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), | ||
677 | iomem, tcpd->irq_base); | ||
678 | |||
679 | if (!ret) | ||
680 | return 0; | ||
681 | |||
682 | if (tcpd->teardown) | ||
683 | tcpd->teardown(dev); | ||
684 | |||
685 | err_setup: | ||
686 | tc6393xb_detach_irq(dev); | ||
687 | |||
688 | err_gpio_add: | ||
689 | if (tc6393xb->gpio.base != -1) | ||
690 | temp = gpiochip_remove(&tc6393xb->gpio); | ||
691 | tcpd->disable(dev); | ||
692 | err_clk_enable: | ||
693 | clk_disable(tc6393xb->clk); | ||
694 | err_enable: | ||
695 | iounmap(tc6393xb->scr); | ||
696 | err_ioremap: | ||
697 | release_resource(&tc6393xb->rscr); | ||
698 | err_request_scr: | ||
699 | clk_put(tc6393xb->clk); | ||
700 | err_noirq: | ||
701 | err_clk_get: | ||
702 | kfree(tc6393xb); | ||
703 | err_kzalloc: | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | static int __devexit tc6393xb_remove(struct platform_device *dev) | ||
708 | { | ||
709 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | ||
710 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
711 | int ret; | ||
712 | |||
713 | mfd_remove_devices(&dev->dev); | ||
714 | |||
715 | if (tcpd->teardown) | ||
716 | tcpd->teardown(dev); | ||
717 | |||
718 | tc6393xb_detach_irq(dev); | ||
719 | |||
720 | if (tc6393xb->gpio.base != -1) { | ||
721 | ret = gpiochip_remove(&tc6393xb->gpio); | ||
722 | if (ret) { | ||
723 | dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret); | ||
724 | return ret; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | ret = tcpd->disable(dev); | ||
729 | clk_disable(tc6393xb->clk); | ||
730 | iounmap(tc6393xb->scr); | ||
731 | release_resource(&tc6393xb->rscr); | ||
732 | platform_set_drvdata(dev, NULL); | ||
733 | clk_put(tc6393xb->clk); | ||
734 | kfree(tc6393xb); | ||
735 | |||
736 | return ret; | ||
737 | } | ||
738 | |||
739 | #ifdef CONFIG_PM | ||
740 | static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) | ||
741 | { | ||
742 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | ||
743 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
744 | int i, ret; | ||
745 | |||
746 | tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); | ||
747 | tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); | ||
748 | |||
749 | for (i = 0; i < 3; i++) { | ||
750 | tc6393xb->suspend_state.gpo_dsr[i] = | ||
751 | ioread8(tc6393xb->scr + SCR_GPO_DSR(i)); | ||
752 | tc6393xb->suspend_state.gpo_doecr[i] = | ||
753 | ioread8(tc6393xb->scr + SCR_GPO_DOECR(i)); | ||
754 | tc6393xb->suspend_state.gpi_bcr[i] = | ||
755 | ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); | ||
756 | } | ||
757 | ret = tcpd->suspend(dev); | ||
758 | clk_disable(tc6393xb->clk); | ||
759 | |||
760 | return ret; | ||
761 | } | ||
762 | |||
763 | static int tc6393xb_resume(struct platform_device *dev) | ||
764 | { | ||
765 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | ||
766 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
767 | int ret; | ||
768 | int i; | ||
769 | |||
770 | clk_enable(tc6393xb->clk); | ||
771 | |||
772 | ret = tcpd->resume(dev); | ||
773 | if (ret) | ||
774 | return ret; | ||
775 | |||
776 | if (!tcpd->resume_restore) | ||
777 | return 0; | ||
778 | |||
779 | iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER); | ||
780 | iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); | ||
781 | iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR); | ||
782 | iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | | ||
783 | SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | | ||
784 | BIT(15), tc6393xb->scr + SCR_MCR); | ||
785 | iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); | ||
786 | iowrite8(0, tc6393xb->scr + SCR_IRR); | ||
787 | iowrite8(0xbf, tc6393xb->scr + SCR_IMR); | ||
788 | |||
789 | for (i = 0; i < 3; i++) { | ||
790 | iowrite8(tc6393xb->suspend_state.gpo_dsr[i], | ||
791 | tc6393xb->scr + SCR_GPO_DSR(i)); | ||
792 | iowrite8(tc6393xb->suspend_state.gpo_doecr[i], | ||
793 | tc6393xb->scr + SCR_GPO_DOECR(i)); | ||
794 | iowrite8(tc6393xb->suspend_state.gpi_bcr[i], | ||
795 | tc6393xb->scr + SCR_GPI_BCR(i)); | ||
796 | } | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | #else | ||
801 | #define tc6393xb_suspend NULL | ||
802 | #define tc6393xb_resume NULL | ||
803 | #endif | ||
804 | |||
805 | static struct platform_driver tc6393xb_driver = { | ||
806 | .probe = tc6393xb_probe, | ||
807 | .remove = __devexit_p(tc6393xb_remove), | ||
808 | .suspend = tc6393xb_suspend, | ||
809 | .resume = tc6393xb_resume, | ||
810 | |||
811 | .driver = { | ||
812 | .name = "tc6393xb", | ||
813 | .owner = THIS_MODULE, | ||
814 | }, | ||
815 | }; | ||
816 | |||
817 | static int __init tc6393xb_init(void) | ||
818 | { | ||
819 | return platform_driver_register(&tc6393xb_driver); | ||
820 | } | ||
821 | |||
822 | static void __exit tc6393xb_exit(void) | ||
823 | { | ||
824 | platform_driver_unregister(&tc6393xb_driver); | ||
825 | } | ||
826 | |||
827 | subsys_initcall(tc6393xb_init); | ||
828 | module_exit(tc6393xb_exit); | ||
829 | |||
830 | MODULE_LICENSE("GPL v2"); | ||
831 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); | ||
832 | MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); | ||
833 | MODULE_ALIAS("platform:tc6393xb"); | ||
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c new file mode 100644 index 000000000000..dd843c4fbcc7 --- /dev/null +++ b/drivers/mfd/twl4030-core.c | |||
@@ -0,0 +1,806 @@ | |||
1 | /* | ||
2 | * twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Modifications to defer interrupt handling to a kernel thread: | ||
7 | * Copyright (C) 2006 MontaVista Software, Inc. | ||
8 | * | ||
9 | * Based on tlv320aic23.c: | ||
10 | * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> | ||
11 | * | ||
12 | * Code cleanup and modifications to IRQ handler. | ||
13 | * by syed khasim <x0khasim@ti.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | */ | ||
29 | |||
30 | #include <linux/init.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/clk.h> | ||
34 | #include <linux/err.h> | ||
35 | |||
36 | #include <linux/i2c.h> | ||
37 | #include <linux/i2c/twl4030.h> | ||
38 | |||
39 | |||
40 | /* | ||
41 | * The TWL4030 "Triton 2" is one of a family of a multi-function "Power | ||
42 | * Management and System Companion Device" chips originally designed for | ||
43 | * use in OMAP2 and OMAP 3 based systems. Its control interfaces use I2C, | ||
44 | * often at around 3 Mbit/sec, including for interrupt handling. | ||
45 | * | ||
46 | * This driver core provides genirq support for the interrupts emitted, | ||
47 | * by the various modules, and exports register access primitives. | ||
48 | * | ||
49 | * FIXME this driver currently requires use of the first interrupt line | ||
50 | * (and associated registers). | ||
51 | */ | ||
52 | |||
53 | #define DRIVER_NAME "twl4030" | ||
54 | |||
55 | #if defined(CONFIG_TWL4030_BCI_BATTERY) || \ | ||
56 | defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) | ||
57 | #define twl_has_bci() true | ||
58 | #else | ||
59 | #define twl_has_bci() false | ||
60 | #endif | ||
61 | |||
62 | #if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE) | ||
63 | #define twl_has_keypad() true | ||
64 | #else | ||
65 | #define twl_has_keypad() false | ||
66 | #endif | ||
67 | |||
68 | #if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE) | ||
69 | #define twl_has_gpio() true | ||
70 | #else | ||
71 | #define twl_has_gpio() false | ||
72 | #endif | ||
73 | |||
74 | #if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) | ||
75 | #define twl_has_madc() true | ||
76 | #else | ||
77 | #define twl_has_madc() false | ||
78 | #endif | ||
79 | |||
80 | #if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE) | ||
81 | #define twl_has_rtc() true | ||
82 | #else | ||
83 | #define twl_has_rtc() false | ||
84 | #endif | ||
85 | |||
86 | #if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) | ||
87 | #define twl_has_usb() true | ||
88 | #else | ||
89 | #define twl_has_usb() false | ||
90 | #endif | ||
91 | |||
92 | |||
93 | /* Triton Core internal information (BEGIN) */ | ||
94 | |||
95 | /* Last - for index max*/ | ||
96 | #define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG | ||
97 | |||
98 | #define TWL4030_NUM_SLAVES 4 | ||
99 | |||
100 | |||
101 | /* Base Address defns for twl4030_map[] */ | ||
102 | |||
103 | /* subchip/slave 0 - USB ID */ | ||
104 | #define TWL4030_BASEADD_USB 0x0000 | ||
105 | |||
106 | /* subchip/slave 1 - AUD ID */ | ||
107 | #define TWL4030_BASEADD_AUDIO_VOICE 0x0000 | ||
108 | #define TWL4030_BASEADD_GPIO 0x0098 | ||
109 | #define TWL4030_BASEADD_INTBR 0x0085 | ||
110 | #define TWL4030_BASEADD_PIH 0x0080 | ||
111 | #define TWL4030_BASEADD_TEST 0x004C | ||
112 | |||
113 | /* subchip/slave 2 - AUX ID */ | ||
114 | #define TWL4030_BASEADD_INTERRUPTS 0x00B9 | ||
115 | #define TWL4030_BASEADD_LED 0x00EE | ||
116 | #define TWL4030_BASEADD_MADC 0x0000 | ||
117 | #define TWL4030_BASEADD_MAIN_CHARGE 0x0074 | ||
118 | #define TWL4030_BASEADD_PRECHARGE 0x00AA | ||
119 | #define TWL4030_BASEADD_PWM0 0x00F8 | ||
120 | #define TWL4030_BASEADD_PWM1 0x00FB | ||
121 | #define TWL4030_BASEADD_PWMA 0x00EF | ||
122 | #define TWL4030_BASEADD_PWMB 0x00F1 | ||
123 | #define TWL4030_BASEADD_KEYPAD 0x00D2 | ||
124 | |||
125 | /* subchip/slave 3 - POWER ID */ | ||
126 | #define TWL4030_BASEADD_BACKUP 0x0014 | ||
127 | #define TWL4030_BASEADD_INT 0x002E | ||
128 | #define TWL4030_BASEADD_PM_MASTER 0x0036 | ||
129 | #define TWL4030_BASEADD_PM_RECEIVER 0x005B | ||
130 | #define TWL4030_BASEADD_RTC 0x001C | ||
131 | #define TWL4030_BASEADD_SECURED_REG 0x0000 | ||
132 | |||
133 | /* Triton Core internal information (END) */ | ||
134 | |||
135 | |||
136 | /* Few power values */ | ||
137 | #define R_CFG_BOOT 0x05 | ||
138 | #define R_PROTECT_KEY 0x0E | ||
139 | |||
140 | /* access control values for R_PROTECT_KEY */ | ||
141 | #define KEY_UNLOCK1 0xce | ||
142 | #define KEY_UNLOCK2 0xec | ||
143 | #define KEY_LOCK 0x00 | ||
144 | |||
145 | /* some fields in R_CFG_BOOT */ | ||
146 | #define HFCLK_FREQ_19p2_MHZ (1 << 0) | ||
147 | #define HFCLK_FREQ_26_MHZ (2 << 0) | ||
148 | #define HFCLK_FREQ_38p4_MHZ (3 << 0) | ||
149 | #define HIGH_PERF_SQ (1 << 3) | ||
150 | |||
151 | |||
152 | /*----------------------------------------------------------------------*/ | ||
153 | |||
154 | /* is driver active, bound to a chip? */ | ||
155 | static bool inuse; | ||
156 | |||
157 | /* Structure for each TWL4030 Slave */ | ||
158 | struct twl4030_client { | ||
159 | struct i2c_client *client; | ||
160 | u8 address; | ||
161 | |||
162 | /* max numb of i2c_msg required is for read =2 */ | ||
163 | struct i2c_msg xfer_msg[2]; | ||
164 | |||
165 | /* To lock access to xfer_msg */ | ||
166 | struct mutex xfer_lock; | ||
167 | }; | ||
168 | |||
169 | static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES]; | ||
170 | |||
171 | |||
172 | /* mapping the module id to slave id and base address */ | ||
173 | struct twl4030mapping { | ||
174 | unsigned char sid; /* Slave ID */ | ||
175 | unsigned char base; /* base address */ | ||
176 | }; | ||
177 | |||
178 | static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | ||
179 | /* | ||
180 | * NOTE: don't change this table without updating the | ||
181 | * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_* | ||
182 | * so they continue to match the order in this table. | ||
183 | */ | ||
184 | |||
185 | { 0, TWL4030_BASEADD_USB }, | ||
186 | |||
187 | { 1, TWL4030_BASEADD_AUDIO_VOICE }, | ||
188 | { 1, TWL4030_BASEADD_GPIO }, | ||
189 | { 1, TWL4030_BASEADD_INTBR }, | ||
190 | { 1, TWL4030_BASEADD_PIH }, | ||
191 | { 1, TWL4030_BASEADD_TEST }, | ||
192 | |||
193 | { 2, TWL4030_BASEADD_KEYPAD }, | ||
194 | { 2, TWL4030_BASEADD_MADC }, | ||
195 | { 2, TWL4030_BASEADD_INTERRUPTS }, | ||
196 | { 2, TWL4030_BASEADD_LED }, | ||
197 | { 2, TWL4030_BASEADD_MAIN_CHARGE }, | ||
198 | { 2, TWL4030_BASEADD_PRECHARGE }, | ||
199 | { 2, TWL4030_BASEADD_PWM0 }, | ||
200 | { 2, TWL4030_BASEADD_PWM1 }, | ||
201 | { 2, TWL4030_BASEADD_PWMA }, | ||
202 | { 2, TWL4030_BASEADD_PWMB }, | ||
203 | |||
204 | { 3, TWL4030_BASEADD_BACKUP }, | ||
205 | { 3, TWL4030_BASEADD_INT }, | ||
206 | { 3, TWL4030_BASEADD_PM_MASTER }, | ||
207 | { 3, TWL4030_BASEADD_PM_RECEIVER }, | ||
208 | { 3, TWL4030_BASEADD_RTC }, | ||
209 | { 3, TWL4030_BASEADD_SECURED_REG }, | ||
210 | }; | ||
211 | |||
212 | /*----------------------------------------------------------------------*/ | ||
213 | |||
214 | /* Exported Functions */ | ||
215 | |||
216 | /** | ||
217 | * twl4030_i2c_write - Writes a n bit register in TWL4030 | ||
218 | * @mod_no: module number | ||
219 | * @value: an array of num_bytes+1 containing data to write | ||
220 | * @reg: register address (just offset will do) | ||
221 | * @num_bytes: number of bytes to transfer | ||
222 | * | ||
223 | * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and | ||
224 | * valid data starts at Offset 1. | ||
225 | * | ||
226 | * Returns the result of operation - 0 is success | ||
227 | */ | ||
228 | int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes) | ||
229 | { | ||
230 | int ret; | ||
231 | int sid; | ||
232 | struct twl4030_client *twl; | ||
233 | struct i2c_msg *msg; | ||
234 | |||
235 | if (unlikely(mod_no > TWL4030_MODULE_LAST)) { | ||
236 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | ||
237 | return -EPERM; | ||
238 | } | ||
239 | sid = twl4030_map[mod_no].sid; | ||
240 | twl = &twl4030_modules[sid]; | ||
241 | |||
242 | if (unlikely(!inuse)) { | ||
243 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); | ||
244 | return -EPERM; | ||
245 | } | ||
246 | mutex_lock(&twl->xfer_lock); | ||
247 | /* | ||
248 | * [MSG1]: fill the register address data | ||
249 | * fill the data Tx buffer | ||
250 | */ | ||
251 | msg = &twl->xfer_msg[0]; | ||
252 | msg->addr = twl->address; | ||
253 | msg->len = num_bytes + 1; | ||
254 | msg->flags = 0; | ||
255 | msg->buf = value; | ||
256 | /* over write the first byte of buffer with the register address */ | ||
257 | *value = twl4030_map[mod_no].base + reg; | ||
258 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); | ||
259 | mutex_unlock(&twl->xfer_lock); | ||
260 | |||
261 | /* i2cTransfer returns num messages.translate it pls.. */ | ||
262 | if (ret >= 0) | ||
263 | ret = 0; | ||
264 | return ret; | ||
265 | } | ||
266 | EXPORT_SYMBOL(twl4030_i2c_write); | ||
267 | |||
268 | /** | ||
269 | * twl4030_i2c_read - Reads a n bit register in TWL4030 | ||
270 | * @mod_no: module number | ||
271 | * @value: an array of num_bytes containing data to be read | ||
272 | * @reg: register address (just offset will do) | ||
273 | * @num_bytes: number of bytes to transfer | ||
274 | * | ||
275 | * Returns result of operation - num_bytes is success else failure. | ||
276 | */ | ||
277 | int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes) | ||
278 | { | ||
279 | int ret; | ||
280 | u8 val; | ||
281 | int sid; | ||
282 | struct twl4030_client *twl; | ||
283 | struct i2c_msg *msg; | ||
284 | |||
285 | if (unlikely(mod_no > TWL4030_MODULE_LAST)) { | ||
286 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | ||
287 | return -EPERM; | ||
288 | } | ||
289 | sid = twl4030_map[mod_no].sid; | ||
290 | twl = &twl4030_modules[sid]; | ||
291 | |||
292 | if (unlikely(!inuse)) { | ||
293 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); | ||
294 | return -EPERM; | ||
295 | } | ||
296 | mutex_lock(&twl->xfer_lock); | ||
297 | /* [MSG1] fill the register address data */ | ||
298 | msg = &twl->xfer_msg[0]; | ||
299 | msg->addr = twl->address; | ||
300 | msg->len = 1; | ||
301 | msg->flags = 0; /* Read the register value */ | ||
302 | val = twl4030_map[mod_no].base + reg; | ||
303 | msg->buf = &val; | ||
304 | /* [MSG2] fill the data rx buffer */ | ||
305 | msg = &twl->xfer_msg[1]; | ||
306 | msg->addr = twl->address; | ||
307 | msg->flags = I2C_M_RD; /* Read the register value */ | ||
308 | msg->len = num_bytes; /* only n bytes */ | ||
309 | msg->buf = value; | ||
310 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2); | ||
311 | mutex_unlock(&twl->xfer_lock); | ||
312 | |||
313 | /* i2cTransfer returns num messages.translate it pls.. */ | ||
314 | if (ret >= 0) | ||
315 | ret = 0; | ||
316 | return ret; | ||
317 | } | ||
318 | EXPORT_SYMBOL(twl4030_i2c_read); | ||
319 | |||
320 | /** | ||
321 | * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030 | ||
322 | * @mod_no: module number | ||
323 | * @value: the value to be written 8 bit | ||
324 | * @reg: register address (just offset will do) | ||
325 | * | ||
326 | * Returns result of operation - 0 is success | ||
327 | */ | ||
328 | int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg) | ||
329 | { | ||
330 | |||
331 | /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */ | ||
332 | u8 temp_buffer[2] = { 0 }; | ||
333 | /* offset 1 contains the data */ | ||
334 | temp_buffer[1] = value; | ||
335 | return twl4030_i2c_write(mod_no, temp_buffer, reg, 1); | ||
336 | } | ||
337 | EXPORT_SYMBOL(twl4030_i2c_write_u8); | ||
338 | |||
339 | /** | ||
340 | * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030 | ||
341 | * @mod_no: module number | ||
342 | * @value: the value read 8 bit | ||
343 | * @reg: register address (just offset will do) | ||
344 | * | ||
345 | * Returns result of operation - 0 is success | ||
346 | */ | ||
347 | int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg) | ||
348 | { | ||
349 | return twl4030_i2c_read(mod_no, value, reg, 1); | ||
350 | } | ||
351 | EXPORT_SYMBOL(twl4030_i2c_read_u8); | ||
352 | |||
353 | /*----------------------------------------------------------------------*/ | ||
354 | |||
355 | /* | ||
356 | * NOTE: We know the first 8 IRQs after pdata->base_irq are | ||
357 | * for the PIH, and the next are for the PWR_INT SIH, since | ||
358 | * that's how twl_init_irq() sets things up. | ||
359 | */ | ||
360 | |||
361 | static int add_children(struct twl4030_platform_data *pdata) | ||
362 | { | ||
363 | struct platform_device *pdev = NULL; | ||
364 | struct twl4030_client *twl = NULL; | ||
365 | int status = 0; | ||
366 | |||
367 | if (twl_has_bci() && pdata->bci) { | ||
368 | twl = &twl4030_modules[3]; | ||
369 | |||
370 | pdev = platform_device_alloc("twl4030_bci", -1); | ||
371 | if (!pdev) { | ||
372 | pr_debug("%s: can't alloc bci dev\n", DRIVER_NAME); | ||
373 | status = -ENOMEM; | ||
374 | goto err; | ||
375 | } | ||
376 | |||
377 | if (status == 0) { | ||
378 | pdev->dev.parent = &twl->client->dev; | ||
379 | status = platform_device_add_data(pdev, pdata->bci, | ||
380 | sizeof(*pdata->bci)); | ||
381 | if (status < 0) { | ||
382 | dev_dbg(&twl->client->dev, | ||
383 | "can't add bci data, %d\n", | ||
384 | status); | ||
385 | goto err; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | if (status == 0) { | ||
390 | struct resource r = { | ||
391 | .start = pdata->irq_base + 8 + 1, | ||
392 | .flags = IORESOURCE_IRQ, | ||
393 | }; | ||
394 | |||
395 | status = platform_device_add_resources(pdev, &r, 1); | ||
396 | } | ||
397 | |||
398 | if (status == 0) | ||
399 | status = platform_device_add(pdev); | ||
400 | |||
401 | if (status < 0) { | ||
402 | platform_device_put(pdev); | ||
403 | dev_dbg(&twl->client->dev, | ||
404 | "can't create bci dev, %d\n", | ||
405 | status); | ||
406 | goto err; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | if (twl_has_gpio() && pdata->gpio) { | ||
411 | twl = &twl4030_modules[1]; | ||
412 | |||
413 | pdev = platform_device_alloc("twl4030_gpio", -1); | ||
414 | if (!pdev) { | ||
415 | pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME); | ||
416 | status = -ENOMEM; | ||
417 | goto err; | ||
418 | } | ||
419 | |||
420 | /* more driver model init */ | ||
421 | if (status == 0) { | ||
422 | pdev->dev.parent = &twl->client->dev; | ||
423 | /* device_init_wakeup(&pdev->dev, 1); */ | ||
424 | |||
425 | status = platform_device_add_data(pdev, pdata->gpio, | ||
426 | sizeof(*pdata->gpio)); | ||
427 | if (status < 0) { | ||
428 | dev_dbg(&twl->client->dev, | ||
429 | "can't add gpio data, %d\n", | ||
430 | status); | ||
431 | goto err; | ||
432 | } | ||
433 | } | ||
434 | |||
435 | /* GPIO module IRQ */ | ||
436 | if (status == 0) { | ||
437 | struct resource r = { | ||
438 | .start = pdata->irq_base + 0, | ||
439 | .flags = IORESOURCE_IRQ, | ||
440 | }; | ||
441 | |||
442 | status = platform_device_add_resources(pdev, &r, 1); | ||
443 | } | ||
444 | |||
445 | if (status == 0) | ||
446 | status = platform_device_add(pdev); | ||
447 | |||
448 | if (status < 0) { | ||
449 | platform_device_put(pdev); | ||
450 | dev_dbg(&twl->client->dev, | ||
451 | "can't create gpio dev, %d\n", | ||
452 | status); | ||
453 | goto err; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | if (twl_has_keypad() && pdata->keypad) { | ||
458 | pdev = platform_device_alloc("twl4030_keypad", -1); | ||
459 | if (pdev) { | ||
460 | twl = &twl4030_modules[2]; | ||
461 | pdev->dev.parent = &twl->client->dev; | ||
462 | device_init_wakeup(&pdev->dev, 1); | ||
463 | status = platform_device_add_data(pdev, pdata->keypad, | ||
464 | sizeof(*pdata->keypad)); | ||
465 | if (status < 0) { | ||
466 | dev_dbg(&twl->client->dev, | ||
467 | "can't add keypad data, %d\n", | ||
468 | status); | ||
469 | platform_device_put(pdev); | ||
470 | goto err; | ||
471 | } | ||
472 | status = platform_device_add(pdev); | ||
473 | if (status < 0) { | ||
474 | platform_device_put(pdev); | ||
475 | dev_dbg(&twl->client->dev, | ||
476 | "can't create keypad dev, %d\n", | ||
477 | status); | ||
478 | goto err; | ||
479 | } | ||
480 | } else { | ||
481 | pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME); | ||
482 | status = -ENOMEM; | ||
483 | goto err; | ||
484 | } | ||
485 | } | ||
486 | |||
487 | if (twl_has_madc() && pdata->madc) { | ||
488 | pdev = platform_device_alloc("twl4030_madc", -1); | ||
489 | if (pdev) { | ||
490 | twl = &twl4030_modules[2]; | ||
491 | pdev->dev.parent = &twl->client->dev; | ||
492 | device_init_wakeup(&pdev->dev, 1); | ||
493 | status = platform_device_add_data(pdev, pdata->madc, | ||
494 | sizeof(*pdata->madc)); | ||
495 | if (status < 0) { | ||
496 | platform_device_put(pdev); | ||
497 | dev_dbg(&twl->client->dev, | ||
498 | "can't add madc data, %d\n", | ||
499 | status); | ||
500 | goto err; | ||
501 | } | ||
502 | status = platform_device_add(pdev); | ||
503 | if (status < 0) { | ||
504 | platform_device_put(pdev); | ||
505 | dev_dbg(&twl->client->dev, | ||
506 | "can't create madc dev, %d\n", | ||
507 | status); | ||
508 | goto err; | ||
509 | } | ||
510 | } else { | ||
511 | pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME); | ||
512 | status = -ENOMEM; | ||
513 | goto err; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | if (twl_has_rtc()) { | ||
518 | twl = &twl4030_modules[3]; | ||
519 | |||
520 | pdev = platform_device_alloc("twl4030_rtc", -1); | ||
521 | if (!pdev) { | ||
522 | pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME); | ||
523 | status = -ENOMEM; | ||
524 | } else { | ||
525 | pdev->dev.parent = &twl->client->dev; | ||
526 | device_init_wakeup(&pdev->dev, 1); | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | * REVISIT platform_data here currently might use of | ||
531 | * "msecure" line ... but for now we just expect board | ||
532 | * setup to tell the chip "we are secure" at all times. | ||
533 | * Eventually, Linux might become more aware of such | ||
534 | * HW security concerns, and "least privilege". | ||
535 | */ | ||
536 | |||
537 | /* RTC module IRQ */ | ||
538 | if (status == 0) { | ||
539 | struct resource r = { | ||
540 | .start = pdata->irq_base + 8 + 3, | ||
541 | .flags = IORESOURCE_IRQ, | ||
542 | }; | ||
543 | |||
544 | status = platform_device_add_resources(pdev, &r, 1); | ||
545 | } | ||
546 | |||
547 | if (status == 0) | ||
548 | status = platform_device_add(pdev); | ||
549 | |||
550 | if (status < 0) { | ||
551 | platform_device_put(pdev); | ||
552 | dev_dbg(&twl->client->dev, | ||
553 | "can't create rtc dev, %d\n", | ||
554 | status); | ||
555 | goto err; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | if (twl_has_usb() && pdata->usb) { | ||
560 | twl = &twl4030_modules[0]; | ||
561 | |||
562 | pdev = platform_device_alloc("twl4030_usb", -1); | ||
563 | if (!pdev) { | ||
564 | pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME); | ||
565 | status = -ENOMEM; | ||
566 | goto err; | ||
567 | } | ||
568 | |||
569 | if (status == 0) { | ||
570 | pdev->dev.parent = &twl->client->dev; | ||
571 | device_init_wakeup(&pdev->dev, 1); | ||
572 | status = platform_device_add_data(pdev, pdata->usb, | ||
573 | sizeof(*pdata->usb)); | ||
574 | if (status < 0) { | ||
575 | platform_device_put(pdev); | ||
576 | dev_dbg(&twl->client->dev, | ||
577 | "can't add usb data, %d\n", | ||
578 | status); | ||
579 | goto err; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | if (status == 0) { | ||
584 | struct resource r = { | ||
585 | .start = pdata->irq_base + 8 + 2, | ||
586 | .flags = IORESOURCE_IRQ, | ||
587 | }; | ||
588 | |||
589 | status = platform_device_add_resources(pdev, &r, 1); | ||
590 | } | ||
591 | |||
592 | if (status == 0) | ||
593 | status = platform_device_add(pdev); | ||
594 | |||
595 | if (status < 0) { | ||
596 | platform_device_put(pdev); | ||
597 | dev_dbg(&twl->client->dev, | ||
598 | "can't create usb dev, %d\n", | ||
599 | status); | ||
600 | } | ||
601 | } | ||
602 | |||
603 | err: | ||
604 | if (status) | ||
605 | pr_err("failed to add twl4030's children (status %d)\n", status); | ||
606 | return status; | ||
607 | } | ||
608 | |||
609 | /*----------------------------------------------------------------------*/ | ||
610 | |||
611 | /* | ||
612 | * These three functions initialize the on-chip clock framework, | ||
613 | * letting it generate the right frequencies for USB, MADC, and | ||
614 | * other purposes. | ||
615 | */ | ||
616 | static inline int __init protect_pm_master(void) | ||
617 | { | ||
618 | int e = 0; | ||
619 | |||
620 | e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK, | ||
621 | R_PROTECT_KEY); | ||
622 | return e; | ||
623 | } | ||
624 | |||
625 | static inline int __init unprotect_pm_master(void) | ||
626 | { | ||
627 | int e = 0; | ||
628 | |||
629 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1, | ||
630 | R_PROTECT_KEY); | ||
631 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2, | ||
632 | R_PROTECT_KEY); | ||
633 | return e; | ||
634 | } | ||
635 | |||
636 | static void __init clocks_init(void) | ||
637 | { | ||
638 | int e = 0; | ||
639 | struct clk *osc; | ||
640 | u32 rate; | ||
641 | u8 ctrl = HFCLK_FREQ_26_MHZ; | ||
642 | |||
643 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) | ||
644 | if (cpu_is_omap2430()) | ||
645 | osc = clk_get(NULL, "osc_ck"); | ||
646 | else | ||
647 | osc = clk_get(NULL, "osc_sys_ck"); | ||
648 | #else | ||
649 | /* REVISIT for non-OMAP systems, pass the clock rate from | ||
650 | * board init code, using platform_data. | ||
651 | */ | ||
652 | osc = ERR_PTR(-EIO); | ||
653 | #endif | ||
654 | if (IS_ERR(osc)) { | ||
655 | printk(KERN_WARNING "Skipping twl4030 internal clock init and " | ||
656 | "using bootloader value (unknown osc rate)\n"); | ||
657 | return; | ||
658 | } | ||
659 | |||
660 | rate = clk_get_rate(osc); | ||
661 | clk_put(osc); | ||
662 | |||
663 | switch (rate) { | ||
664 | case 19200000: | ||
665 | ctrl = HFCLK_FREQ_19p2_MHZ; | ||
666 | break; | ||
667 | case 26000000: | ||
668 | ctrl = HFCLK_FREQ_26_MHZ; | ||
669 | break; | ||
670 | case 38400000: | ||
671 | ctrl = HFCLK_FREQ_38p4_MHZ; | ||
672 | break; | ||
673 | } | ||
674 | |||
675 | ctrl |= HIGH_PERF_SQ; | ||
676 | e |= unprotect_pm_master(); | ||
677 | /* effect->MADC+USB ck en */ | ||
678 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); | ||
679 | e |= protect_pm_master(); | ||
680 | |||
681 | if (e < 0) | ||
682 | pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e); | ||
683 | } | ||
684 | |||
685 | /*----------------------------------------------------------------------*/ | ||
686 | |||
687 | int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
688 | int twl_exit_irq(void); | ||
689 | |||
690 | static int twl4030_remove(struct i2c_client *client) | ||
691 | { | ||
692 | unsigned i; | ||
693 | int status; | ||
694 | |||
695 | status = twl_exit_irq(); | ||
696 | if (status < 0) | ||
697 | return status; | ||
698 | |||
699 | for (i = 0; i < TWL4030_NUM_SLAVES; i++) { | ||
700 | struct twl4030_client *twl = &twl4030_modules[i]; | ||
701 | |||
702 | if (twl->client && twl->client != client) | ||
703 | i2c_unregister_device(twl->client); | ||
704 | twl4030_modules[i].client = NULL; | ||
705 | } | ||
706 | inuse = false; | ||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ | ||
711 | static int | ||
712 | twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
713 | { | ||
714 | int status; | ||
715 | unsigned i; | ||
716 | struct twl4030_platform_data *pdata = client->dev.platform_data; | ||
717 | |||
718 | if (!pdata) { | ||
719 | dev_dbg(&client->dev, "no platform data?\n"); | ||
720 | return -EINVAL; | ||
721 | } | ||
722 | |||
723 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { | ||
724 | dev_dbg(&client->dev, "can't talk I2C?\n"); | ||
725 | return -EIO; | ||
726 | } | ||
727 | |||
728 | if (inuse) { | ||
729 | dev_dbg(&client->dev, "driver is already in use\n"); | ||
730 | return -EBUSY; | ||
731 | } | ||
732 | |||
733 | for (i = 0; i < TWL4030_NUM_SLAVES; i++) { | ||
734 | struct twl4030_client *twl = &twl4030_modules[i]; | ||
735 | |||
736 | twl->address = client->addr + i; | ||
737 | if (i == 0) | ||
738 | twl->client = client; | ||
739 | else { | ||
740 | twl->client = i2c_new_dummy(client->adapter, | ||
741 | twl->address); | ||
742 | if (!twl->client) { | ||
743 | dev_err(&twl->client->dev, | ||
744 | "can't attach client %d\n", i); | ||
745 | status = -ENOMEM; | ||
746 | goto fail; | ||
747 | } | ||
748 | strlcpy(twl->client->name, id->name, | ||
749 | sizeof(twl->client->name)); | ||
750 | } | ||
751 | mutex_init(&twl->xfer_lock); | ||
752 | } | ||
753 | inuse = true; | ||
754 | |||
755 | /* setup clock framework */ | ||
756 | clocks_init(); | ||
757 | |||
758 | /* Maybe init the T2 Interrupt subsystem */ | ||
759 | if (client->irq | ||
760 | && pdata->irq_base | ||
761 | && pdata->irq_end > pdata->irq_base) { | ||
762 | status = twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end); | ||
763 | if (status < 0) | ||
764 | goto fail; | ||
765 | } | ||
766 | |||
767 | status = add_children(pdata); | ||
768 | fail: | ||
769 | if (status < 0) | ||
770 | twl4030_remove(client); | ||
771 | return status; | ||
772 | } | ||
773 | |||
774 | static const struct i2c_device_id twl4030_ids[] = { | ||
775 | { "twl4030", 0 }, /* "Triton 2" */ | ||
776 | { "tps65950", 0 }, /* catalog version of twl4030 */ | ||
777 | { "tps65930", 0 }, /* fewer LDOs and DACs; no charger */ | ||
778 | { "tps65920", 0 }, /* fewer LDOs; no codec or charger */ | ||
779 | { "twl5030", 0 }, /* T2 updated */ | ||
780 | { /* end of list */ }, | ||
781 | }; | ||
782 | MODULE_DEVICE_TABLE(i2c, twl4030_ids); | ||
783 | |||
784 | /* One Client Driver , 4 Clients */ | ||
785 | static struct i2c_driver twl4030_driver = { | ||
786 | .driver.name = DRIVER_NAME, | ||
787 | .id_table = twl4030_ids, | ||
788 | .probe = twl4030_probe, | ||
789 | .remove = twl4030_remove, | ||
790 | }; | ||
791 | |||
792 | static int __init twl4030_init(void) | ||
793 | { | ||
794 | return i2c_add_driver(&twl4030_driver); | ||
795 | } | ||
796 | subsys_initcall(twl4030_init); | ||
797 | |||
798 | static void __exit twl4030_exit(void) | ||
799 | { | ||
800 | i2c_del_driver(&twl4030_driver); | ||
801 | } | ||
802 | module_exit(twl4030_exit); | ||
803 | |||
804 | MODULE_AUTHOR("Texas Instruments, Inc."); | ||
805 | MODULE_DESCRIPTION("I2C Core interface for TWL4030"); | ||
806 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c new file mode 100644 index 000000000000..fae868a8d499 --- /dev/null +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -0,0 +1,743 @@ | |||
1 | /* | ||
2 | * twl4030-irq.c - TWL4030/TPS659x0 irq support | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Modifications to defer interrupt handling to a kernel thread: | ||
7 | * Copyright (C) 2006 MontaVista Software, Inc. | ||
8 | * | ||
9 | * Based on tlv320aic23.c: | ||
10 | * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> | ||
11 | * | ||
12 | * Code cleanup and modifications to IRQ handler. | ||
13 | * by syed khasim <x0khasim@ti.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | */ | ||
29 | |||
30 | #include <linux/init.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/irq.h> | ||
33 | #include <linux/kthread.h> | ||
34 | |||
35 | #include <linux/i2c/twl4030.h> | ||
36 | |||
37 | |||
38 | /* | ||
39 | * TWL4030 IRQ handling has two stages in hardware, and thus in software. | ||
40 | * The Primary Interrupt Handler (PIH) stage exposes status bits saying | ||
41 | * which Secondary Interrupt Handler (SIH) stage is raising an interrupt. | ||
42 | * SIH modules are more traditional IRQ components, which support per-IRQ | ||
43 | * enable/disable and trigger controls; they do most of the work. | ||
44 | * | ||
45 | * These chips are designed to support IRQ handling from two different | ||
46 | * I2C masters. Each has a dedicated IRQ line, and dedicated IRQ status | ||
47 | * and mask registers in the PIH and SIH modules. | ||
48 | * | ||
49 | * We set up IRQs starting at a platform-specified base, always starting | ||
50 | * with PIH and the SIH for PWR_INT and then usually adding GPIO: | ||
51 | * base + 0 .. base + 7 PIH | ||
52 | * base + 8 .. base + 15 SIH for PWR_INT | ||
53 | * base + 16 .. base + 33 SIH for GPIO | ||
54 | */ | ||
55 | |||
56 | /* PIH register offsets */ | ||
57 | #define REG_PIH_ISR_P1 0x01 | ||
58 | #define REG_PIH_ISR_P2 0x02 | ||
59 | #define REG_PIH_SIR 0x03 /* for testing */ | ||
60 | |||
61 | |||
62 | /* Linux could (eventually) use either IRQ line */ | ||
63 | static int irq_line; | ||
64 | |||
65 | struct sih { | ||
66 | char name[8]; | ||
67 | u8 module; /* module id */ | ||
68 | u8 control_offset; /* for SIH_CTRL */ | ||
69 | bool set_cor; | ||
70 | |||
71 | u8 bits; /* valid in isr/imr */ | ||
72 | u8 bytes_ixr; /* bytelen of ISR/IMR/SIR */ | ||
73 | |||
74 | u8 edr_offset; | ||
75 | u8 bytes_edr; /* bytelen of EDR */ | ||
76 | |||
77 | /* SIR ignored -- set interrupt, for testing only */ | ||
78 | struct irq_data { | ||
79 | u8 isr_offset; | ||
80 | u8 imr_offset; | ||
81 | } mask[2]; | ||
82 | /* + 2 bytes padding */ | ||
83 | }; | ||
84 | |||
85 | #define SIH_INITIALIZER(modname, nbits) \ | ||
86 | .module = TWL4030_MODULE_ ## modname, \ | ||
87 | .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \ | ||
88 | .bits = nbits, \ | ||
89 | .bytes_ixr = DIV_ROUND_UP(nbits, 8), \ | ||
90 | .edr_offset = TWL4030_ ## modname ## _EDR, \ | ||
91 | .bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \ | ||
92 | .mask = { { \ | ||
93 | .isr_offset = TWL4030_ ## modname ## _ISR1, \ | ||
94 | .imr_offset = TWL4030_ ## modname ## _IMR1, \ | ||
95 | }, \ | ||
96 | { \ | ||
97 | .isr_offset = TWL4030_ ## modname ## _ISR2, \ | ||
98 | .imr_offset = TWL4030_ ## modname ## _IMR2, \ | ||
99 | }, }, | ||
100 | |||
101 | /* register naming policies are inconsistent ... */ | ||
102 | #define TWL4030_INT_PWR_EDR TWL4030_INT_PWR_EDR1 | ||
103 | #define TWL4030_MODULE_KEYPAD_KEYP TWL4030_MODULE_KEYPAD | ||
104 | #define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT | ||
105 | |||
106 | |||
107 | /* Order in this table matches order in PIH_ISR. That is, | ||
108 | * BIT(n) in PIH_ISR is sih_modules[n]. | ||
109 | */ | ||
110 | static const struct sih sih_modules[6] = { | ||
111 | [0] = { | ||
112 | .name = "gpio", | ||
113 | .module = TWL4030_MODULE_GPIO, | ||
114 | .control_offset = REG_GPIO_SIH_CTRL, | ||
115 | .set_cor = true, | ||
116 | .bits = TWL4030_GPIO_MAX, | ||
117 | .bytes_ixr = 3, | ||
118 | /* Note: *all* of these IRQs default to no-trigger */ | ||
119 | .edr_offset = REG_GPIO_EDR1, | ||
120 | .bytes_edr = 5, | ||
121 | .mask = { { | ||
122 | .isr_offset = REG_GPIO_ISR1A, | ||
123 | .imr_offset = REG_GPIO_IMR1A, | ||
124 | }, { | ||
125 | .isr_offset = REG_GPIO_ISR1B, | ||
126 | .imr_offset = REG_GPIO_IMR1B, | ||
127 | }, }, | ||
128 | }, | ||
129 | [1] = { | ||
130 | .name = "keypad", | ||
131 | .set_cor = true, | ||
132 | SIH_INITIALIZER(KEYPAD_KEYP, 4) | ||
133 | }, | ||
134 | [2] = { | ||
135 | .name = "bci", | ||
136 | .module = TWL4030_MODULE_INTERRUPTS, | ||
137 | .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL, | ||
138 | .bits = 12, | ||
139 | .bytes_ixr = 2, | ||
140 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, | ||
141 | /* Note: most of these IRQs default to no-trigger */ | ||
142 | .bytes_edr = 3, | ||
143 | .mask = { { | ||
144 | .isr_offset = TWL4030_INTERRUPTS_BCIISR1A, | ||
145 | .imr_offset = TWL4030_INTERRUPTS_BCIIMR1A, | ||
146 | }, { | ||
147 | .isr_offset = TWL4030_INTERRUPTS_BCIISR1B, | ||
148 | .imr_offset = TWL4030_INTERRUPTS_BCIIMR1B, | ||
149 | }, }, | ||
150 | }, | ||
151 | [3] = { | ||
152 | .name = "madc", | ||
153 | SIH_INITIALIZER(MADC, 4) | ||
154 | }, | ||
155 | [4] = { | ||
156 | /* USB doesn't use the same SIH organization */ | ||
157 | .name = "usb", | ||
158 | }, | ||
159 | [5] = { | ||
160 | .name = "power", | ||
161 | .set_cor = true, | ||
162 | SIH_INITIALIZER(INT_PWR, 8) | ||
163 | }, | ||
164 | /* there are no SIH modules #6 or #7 ... */ | ||
165 | }; | ||
166 | |||
167 | #undef TWL4030_MODULE_KEYPAD_KEYP | ||
168 | #undef TWL4030_MODULE_INT_PWR | ||
169 | #undef TWL4030_INT_PWR_EDR | ||
170 | |||
171 | /*----------------------------------------------------------------------*/ | ||
172 | |||
173 | static unsigned twl4030_irq_base; | ||
174 | |||
175 | static struct completion irq_event; | ||
176 | |||
177 | /* | ||
178 | * This thread processes interrupts reported by the Primary Interrupt Handler. | ||
179 | */ | ||
180 | static int twl4030_irq_thread(void *data) | ||
181 | { | ||
182 | long irq = (long)data; | ||
183 | irq_desc_t *desc = irq_desc + irq; | ||
184 | static unsigned i2c_errors; | ||
185 | const static unsigned max_i2c_errors = 100; | ||
186 | |||
187 | current->flags |= PF_NOFREEZE; | ||
188 | |||
189 | while (!kthread_should_stop()) { | ||
190 | int ret; | ||
191 | int module_irq; | ||
192 | u8 pih_isr; | ||
193 | |||
194 | /* Wait for IRQ, then read PIH irq status (also blocking) */ | ||
195 | wait_for_completion_interruptible(&irq_event); | ||
196 | |||
197 | ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr, | ||
198 | REG_PIH_ISR_P1); | ||
199 | if (ret) { | ||
200 | pr_warning("twl4030: I2C error %d reading PIH ISR\n", | ||
201 | ret); | ||
202 | if (++i2c_errors >= max_i2c_errors) { | ||
203 | printk(KERN_ERR "Maximum I2C error count" | ||
204 | " exceeded. Terminating %s.\n", | ||
205 | __func__); | ||
206 | break; | ||
207 | } | ||
208 | complete(&irq_event); | ||
209 | continue; | ||
210 | } | ||
211 | |||
212 | /* these handlers deal with the relevant SIH irq status */ | ||
213 | local_irq_disable(); | ||
214 | for (module_irq = twl4030_irq_base; | ||
215 | pih_isr; | ||
216 | pih_isr >>= 1, module_irq++) { | ||
217 | if (pih_isr & 0x1) { | ||
218 | irq_desc_t *d = irq_desc + module_irq; | ||
219 | |||
220 | /* These can't be masked ... always warn | ||
221 | * if we get any surprises. | ||
222 | */ | ||
223 | if (d->status & IRQ_DISABLED) | ||
224 | note_interrupt(module_irq, d, | ||
225 | IRQ_NONE); | ||
226 | else | ||
227 | d->handle_irq(module_irq, d); | ||
228 | } | ||
229 | } | ||
230 | local_irq_enable(); | ||
231 | |||
232 | desc->chip->unmask(irq); | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * handle_twl4030_pih() is the desc->handle method for the twl4030 interrupt. | ||
240 | * This is a chained interrupt, so there is no desc->action method for it. | ||
241 | * Now we need to query the interrupt controller in the twl4030 to determine | ||
242 | * which module is generating the interrupt request. However, we can't do i2c | ||
243 | * transactions in interrupt context, so we must defer that work to a kernel | ||
244 | * thread. All we do here is acknowledge and mask the interrupt and wakeup | ||
245 | * the kernel thread. | ||
246 | */ | ||
247 | static void handle_twl4030_pih(unsigned int irq, irq_desc_t *desc) | ||
248 | { | ||
249 | /* Acknowledge, clear *AND* mask the interrupt... */ | ||
250 | desc->chip->ack(irq); | ||
251 | complete(&irq_event); | ||
252 | } | ||
253 | |||
254 | static struct task_struct *start_twl4030_irq_thread(long irq) | ||
255 | { | ||
256 | struct task_struct *thread; | ||
257 | |||
258 | init_completion(&irq_event); | ||
259 | thread = kthread_run(twl4030_irq_thread, (void *)irq, "twl4030-irq"); | ||
260 | if (!thread) | ||
261 | pr_err("twl4030: could not create irq %ld thread!\n", irq); | ||
262 | |||
263 | return thread; | ||
264 | } | ||
265 | |||
266 | /*----------------------------------------------------------------------*/ | ||
267 | |||
268 | /* | ||
269 | * twl4030_init_sih_modules() ... start from a known state where no | ||
270 | * IRQs will be coming in, and where we can quickly enable them then | ||
271 | * handle them as they arrive. Mask all IRQs: maybe init SIH_CTRL. | ||
272 | * | ||
273 | * NOTE: we don't touch EDR registers here; they stay with hardware | ||
274 | * defaults or whatever the last value was. Note that when both EDR | ||
275 | * bits for an IRQ are clear, that's as if its IMR bit is set... | ||
276 | */ | ||
277 | static int twl4030_init_sih_modules(unsigned line) | ||
278 | { | ||
279 | const struct sih *sih; | ||
280 | u8 buf[4]; | ||
281 | int i; | ||
282 | int status; | ||
283 | |||
284 | /* line 0 == int1_n signal; line 1 == int2_n signal */ | ||
285 | if (line > 1) | ||
286 | return -EINVAL; | ||
287 | |||
288 | irq_line = line; | ||
289 | |||
290 | /* disable all interrupts on our line */ | ||
291 | memset(buf, 0xff, sizeof buf); | ||
292 | sih = sih_modules; | ||
293 | for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) { | ||
294 | |||
295 | /* skip USB -- it's funky */ | ||
296 | if (!sih->bytes_ixr) | ||
297 | continue; | ||
298 | |||
299 | status = twl4030_i2c_write(sih->module, buf, | ||
300 | sih->mask[line].imr_offset, sih->bytes_ixr); | ||
301 | if (status < 0) | ||
302 | pr_err("twl4030: err %d initializing %s %s\n", | ||
303 | status, sih->name, "IMR"); | ||
304 | |||
305 | /* Maybe disable "exclusive" mode; buffer second pending irq; | ||
306 | * set Clear-On-Read (COR) bit. | ||
307 | * | ||
308 | * NOTE that sometimes COR polarity is documented as being | ||
309 | * inverted: for MADC and BCI, COR=1 means "clear on write". | ||
310 | * And for PWR_INT it's not documented... | ||
311 | */ | ||
312 | if (sih->set_cor) { | ||
313 | status = twl4030_i2c_write_u8(sih->module, | ||
314 | TWL4030_SIH_CTRL_COR_MASK, | ||
315 | sih->control_offset); | ||
316 | if (status < 0) | ||
317 | pr_err("twl4030: err %d initializing %s %s\n", | ||
318 | status, sih->name, "SIH_CTRL"); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | sih = sih_modules; | ||
323 | for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) { | ||
324 | u8 rxbuf[4]; | ||
325 | int j; | ||
326 | |||
327 | /* skip USB */ | ||
328 | if (!sih->bytes_ixr) | ||
329 | continue; | ||
330 | |||
331 | /* Clear pending interrupt status. Either the read was | ||
332 | * enough, or we need to write those bits. Repeat, in | ||
333 | * case an IRQ is pending (PENDDIS=0) ... that's not | ||
334 | * uncommon with PWR_INT.PWRON. | ||
335 | */ | ||
336 | for (j = 0; j < 2; j++) { | ||
337 | status = twl4030_i2c_read(sih->module, rxbuf, | ||
338 | sih->mask[line].isr_offset, sih->bytes_ixr); | ||
339 | if (status < 0) | ||
340 | pr_err("twl4030: err %d initializing %s %s\n", | ||
341 | status, sih->name, "ISR"); | ||
342 | |||
343 | if (!sih->set_cor) | ||
344 | status = twl4030_i2c_write(sih->module, buf, | ||
345 | sih->mask[line].isr_offset, | ||
346 | sih->bytes_ixr); | ||
347 | /* else COR=1 means read sufficed. | ||
348 | * (for most SIH modules...) | ||
349 | */ | ||
350 | } | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static inline void activate_irq(int irq) | ||
357 | { | ||
358 | #ifdef CONFIG_ARM | ||
359 | /* ARM requires an extra step to clear IRQ_NOREQUEST, which it | ||
360 | * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. | ||
361 | */ | ||
362 | set_irq_flags(irq, IRQF_VALID); | ||
363 | #else | ||
364 | /* same effect on other architectures */ | ||
365 | set_irq_noprobe(irq); | ||
366 | #endif | ||
367 | } | ||
368 | |||
369 | /*----------------------------------------------------------------------*/ | ||
370 | |||
371 | static DEFINE_SPINLOCK(sih_agent_lock); | ||
372 | |||
373 | static struct workqueue_struct *wq; | ||
374 | |||
375 | struct sih_agent { | ||
376 | int irq_base; | ||
377 | const struct sih *sih; | ||
378 | |||
379 | u32 imr; | ||
380 | bool imr_change_pending; | ||
381 | struct work_struct mask_work; | ||
382 | |||
383 | u32 edge_change; | ||
384 | struct work_struct edge_work; | ||
385 | }; | ||
386 | |||
387 | static void twl4030_sih_do_mask(struct work_struct *work) | ||
388 | { | ||
389 | struct sih_agent *agent; | ||
390 | const struct sih *sih; | ||
391 | union { | ||
392 | u8 bytes[4]; | ||
393 | u32 word; | ||
394 | } imr; | ||
395 | int status; | ||
396 | |||
397 | agent = container_of(work, struct sih_agent, mask_work); | ||
398 | |||
399 | /* see what work we have */ | ||
400 | spin_lock_irq(&sih_agent_lock); | ||
401 | if (agent->imr_change_pending) { | ||
402 | sih = agent->sih; | ||
403 | /* byte[0] gets overwritten as we write ... */ | ||
404 | imr.word = cpu_to_le32(agent->imr << 8); | ||
405 | agent->imr_change_pending = false; | ||
406 | } else | ||
407 | sih = NULL; | ||
408 | spin_unlock_irq(&sih_agent_lock); | ||
409 | if (!sih) | ||
410 | return; | ||
411 | |||
412 | /* write the whole mask ... simpler than subsetting it */ | ||
413 | status = twl4030_i2c_write(sih->module, imr.bytes, | ||
414 | sih->mask[irq_line].imr_offset, sih->bytes_ixr); | ||
415 | if (status) | ||
416 | pr_err("twl4030: %s, %s --> %d\n", __func__, | ||
417 | "write", status); | ||
418 | } | ||
419 | |||
420 | static void twl4030_sih_do_edge(struct work_struct *work) | ||
421 | { | ||
422 | struct sih_agent *agent; | ||
423 | const struct sih *sih; | ||
424 | u8 bytes[6]; | ||
425 | u32 edge_change; | ||
426 | int status; | ||
427 | |||
428 | agent = container_of(work, struct sih_agent, edge_work); | ||
429 | |||
430 | /* see what work we have */ | ||
431 | spin_lock_irq(&sih_agent_lock); | ||
432 | edge_change = agent->edge_change; | ||
433 | agent->edge_change = 0;; | ||
434 | sih = edge_change ? agent->sih : NULL; | ||
435 | spin_unlock_irq(&sih_agent_lock); | ||
436 | if (!sih) | ||
437 | return; | ||
438 | |||
439 | /* Read, reserving first byte for write scratch. Yes, this | ||
440 | * could be cached for some speedup ... but be careful about | ||
441 | * any processor on the other IRQ line, EDR registers are | ||
442 | * shared. | ||
443 | */ | ||
444 | status = twl4030_i2c_read(sih->module, bytes + 1, | ||
445 | sih->edr_offset, sih->bytes_edr); | ||
446 | if (status) { | ||
447 | pr_err("twl4030: %s, %s --> %d\n", __func__, | ||
448 | "read", status); | ||
449 | return; | ||
450 | } | ||
451 | |||
452 | /* Modify only the bits we know must change */ | ||
453 | while (edge_change) { | ||
454 | int i = fls(edge_change) - 1; | ||
455 | struct irq_desc *d = irq_desc + i + agent->irq_base; | ||
456 | int byte = 1 + (i >> 2); | ||
457 | int off = (i & 0x3) * 2; | ||
458 | |||
459 | bytes[byte] &= ~(0x03 << off); | ||
460 | |||
461 | spin_lock_irq(&d->lock); | ||
462 | if (d->status & IRQ_TYPE_EDGE_RISING) | ||
463 | bytes[byte] |= BIT(off + 1); | ||
464 | if (d->status & IRQ_TYPE_EDGE_FALLING) | ||
465 | bytes[byte] |= BIT(off + 0); | ||
466 | spin_unlock_irq(&d->lock); | ||
467 | |||
468 | edge_change &= ~BIT(i); | ||
469 | } | ||
470 | |||
471 | /* Write */ | ||
472 | status = twl4030_i2c_write(sih->module, bytes, | ||
473 | sih->edr_offset, sih->bytes_edr); | ||
474 | if (status) | ||
475 | pr_err("twl4030: %s, %s --> %d\n", __func__, | ||
476 | "write", status); | ||
477 | } | ||
478 | |||
479 | /*----------------------------------------------------------------------*/ | ||
480 | |||
481 | /* | ||
482 | * All irq_chip methods get issued from code holding irq_desc[irq].lock, | ||
483 | * which can't perform the underlying I2C operations (because they sleep). | ||
484 | * So we must hand them off to a thread (workqueue) and cope with asynch | ||
485 | * completion, potentially including some re-ordering, of these requests. | ||
486 | */ | ||
487 | |||
488 | static void twl4030_sih_mask(unsigned irq) | ||
489 | { | ||
490 | struct sih_agent *sih = get_irq_chip_data(irq); | ||
491 | unsigned long flags; | ||
492 | |||
493 | spin_lock_irqsave(&sih_agent_lock, flags); | ||
494 | sih->imr |= BIT(irq - sih->irq_base); | ||
495 | sih->imr_change_pending = true; | ||
496 | queue_work(wq, &sih->mask_work); | ||
497 | spin_unlock_irqrestore(&sih_agent_lock, flags); | ||
498 | } | ||
499 | |||
500 | static void twl4030_sih_unmask(unsigned irq) | ||
501 | { | ||
502 | struct sih_agent *sih = get_irq_chip_data(irq); | ||
503 | unsigned long flags; | ||
504 | |||
505 | spin_lock_irqsave(&sih_agent_lock, flags); | ||
506 | sih->imr &= ~BIT(irq - sih->irq_base); | ||
507 | sih->imr_change_pending = true; | ||
508 | queue_work(wq, &sih->mask_work); | ||
509 | spin_unlock_irqrestore(&sih_agent_lock, flags); | ||
510 | } | ||
511 | |||
512 | static int twl4030_sih_set_type(unsigned irq, unsigned trigger) | ||
513 | { | ||
514 | struct sih_agent *sih = get_irq_chip_data(irq); | ||
515 | struct irq_desc *desc = irq_desc + irq; | ||
516 | unsigned long flags; | ||
517 | |||
518 | if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | ||
519 | return -EINVAL; | ||
520 | |||
521 | spin_lock_irqsave(&sih_agent_lock, flags); | ||
522 | if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) { | ||
523 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | ||
524 | desc->status |= trigger; | ||
525 | sih->edge_change |= BIT(irq - sih->irq_base); | ||
526 | queue_work(wq, &sih->edge_work); | ||
527 | } | ||
528 | spin_unlock_irqrestore(&sih_agent_lock, flags); | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static struct irq_chip twl4030_sih_irq_chip = { | ||
533 | .name = "twl4030", | ||
534 | .mask = twl4030_sih_mask, | ||
535 | .unmask = twl4030_sih_unmask, | ||
536 | .set_type = twl4030_sih_set_type, | ||
537 | }; | ||
538 | |||
539 | /*----------------------------------------------------------------------*/ | ||
540 | |||
541 | static inline int sih_read_isr(const struct sih *sih) | ||
542 | { | ||
543 | int status; | ||
544 | union { | ||
545 | u8 bytes[4]; | ||
546 | u32 word; | ||
547 | } isr; | ||
548 | |||
549 | /* FIXME need retry-on-error ... */ | ||
550 | |||
551 | isr.word = 0; | ||
552 | status = twl4030_i2c_read(sih->module, isr.bytes, | ||
553 | sih->mask[irq_line].isr_offset, sih->bytes_ixr); | ||
554 | |||
555 | return (status < 0) ? status : le32_to_cpu(isr.word); | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Generic handler for SIH interrupts ... we "know" this is called | ||
560 | * in task context, with IRQs enabled. | ||
561 | */ | ||
562 | static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) | ||
563 | { | ||
564 | struct sih_agent *agent = get_irq_data(irq); | ||
565 | const struct sih *sih = agent->sih; | ||
566 | int isr; | ||
567 | |||
568 | /* reading ISR acks the IRQs, using clear-on-read mode */ | ||
569 | local_irq_enable(); | ||
570 | isr = sih_read_isr(sih); | ||
571 | local_irq_disable(); | ||
572 | |||
573 | if (isr < 0) { | ||
574 | pr_err("twl4030: %s SIH, read ISR error %d\n", | ||
575 | sih->name, isr); | ||
576 | /* REVISIT: recover; eventually mask it all, etc */ | ||
577 | return; | ||
578 | } | ||
579 | |||
580 | while (isr) { | ||
581 | irq = fls(isr); | ||
582 | irq--; | ||
583 | isr &= ~BIT(irq); | ||
584 | |||
585 | if (irq < sih->bits) | ||
586 | generic_handle_irq(agent->irq_base + irq); | ||
587 | else | ||
588 | pr_err("twl4030: %s SIH, invalid ISR bit %d\n", | ||
589 | sih->name, irq); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | static unsigned twl4030_irq_next; | ||
594 | |||
595 | /* returns the first IRQ used by this SIH bank, | ||
596 | * or negative errno | ||
597 | */ | ||
598 | int twl4030_sih_setup(int module) | ||
599 | { | ||
600 | int sih_mod; | ||
601 | const struct sih *sih = NULL; | ||
602 | struct sih_agent *agent; | ||
603 | int i, irq; | ||
604 | int status = -EINVAL; | ||
605 | unsigned irq_base = twl4030_irq_next; | ||
606 | |||
607 | /* only support modules with standard clear-on-read for now */ | ||
608 | for (sih_mod = 0, sih = sih_modules; | ||
609 | sih_mod < ARRAY_SIZE(sih_modules); | ||
610 | sih_mod++, sih++) { | ||
611 | if (sih->module == module && sih->set_cor) { | ||
612 | if (!WARN((irq_base + sih->bits) > NR_IRQS, | ||
613 | "irq %d for %s too big\n", | ||
614 | irq_base + sih->bits, | ||
615 | sih->name)) | ||
616 | status = 0; | ||
617 | break; | ||
618 | } | ||
619 | } | ||
620 | if (status < 0) | ||
621 | return status; | ||
622 | |||
623 | agent = kzalloc(sizeof *agent, GFP_KERNEL); | ||
624 | if (!agent) | ||
625 | return -ENOMEM; | ||
626 | |||
627 | status = 0; | ||
628 | |||
629 | agent->irq_base = irq_base; | ||
630 | agent->sih = sih; | ||
631 | agent->imr = ~0; | ||
632 | INIT_WORK(&agent->mask_work, twl4030_sih_do_mask); | ||
633 | INIT_WORK(&agent->edge_work, twl4030_sih_do_edge); | ||
634 | |||
635 | for (i = 0; i < sih->bits; i++) { | ||
636 | irq = irq_base + i; | ||
637 | |||
638 | set_irq_chip_and_handler(irq, &twl4030_sih_irq_chip, | ||
639 | handle_edge_irq); | ||
640 | set_irq_chip_data(irq, agent); | ||
641 | activate_irq(irq); | ||
642 | } | ||
643 | |||
644 | status = irq_base; | ||
645 | twl4030_irq_next += i; | ||
646 | |||
647 | /* replace generic PIH handler (handle_simple_irq) */ | ||
648 | irq = sih_mod + twl4030_irq_base; | ||
649 | set_irq_data(irq, agent); | ||
650 | set_irq_chained_handler(irq, handle_twl4030_sih); | ||
651 | |||
652 | pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, | ||
653 | irq, irq_base, twl4030_irq_next - 1); | ||
654 | |||
655 | return status; | ||
656 | } | ||
657 | |||
658 | /* FIXME need a call to reverse twl4030_sih_setup() ... */ | ||
659 | |||
660 | |||
661 | /*----------------------------------------------------------------------*/ | ||
662 | |||
663 | /* FIXME pass in which interrupt line we'll use ... */ | ||
664 | #define twl_irq_line 0 | ||
665 | |||
666 | int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | ||
667 | { | ||
668 | static struct irq_chip twl4030_irq_chip; | ||
669 | |||
670 | int status; | ||
671 | int i; | ||
672 | struct task_struct *task; | ||
673 | |||
674 | /* | ||
675 | * Mask and clear all TWL4030 interrupts since initially we do | ||
676 | * not have any TWL4030 module interrupt handlers present | ||
677 | */ | ||
678 | status = twl4030_init_sih_modules(twl_irq_line); | ||
679 | if (status < 0) | ||
680 | return status; | ||
681 | |||
682 | wq = create_singlethread_workqueue("twl4030-irqchip"); | ||
683 | if (!wq) { | ||
684 | pr_err("twl4030: workqueue FAIL\n"); | ||
685 | return -ESRCH; | ||
686 | } | ||
687 | |||
688 | twl4030_irq_base = irq_base; | ||
689 | |||
690 | /* install an irq handler for each of the SIH modules; | ||
691 | * clone dummy irq_chip since PIH can't *do* anything | ||
692 | */ | ||
693 | twl4030_irq_chip = dummy_irq_chip; | ||
694 | twl4030_irq_chip.name = "twl4030"; | ||
695 | |||
696 | twl4030_sih_irq_chip.ack = dummy_irq_chip.ack; | ||
697 | |||
698 | for (i = irq_base; i < irq_end; i++) { | ||
699 | set_irq_chip_and_handler(i, &twl4030_irq_chip, | ||
700 | handle_simple_irq); | ||
701 | activate_irq(i); | ||
702 | } | ||
703 | twl4030_irq_next = i; | ||
704 | pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", | ||
705 | irq_num, irq_base, twl4030_irq_next - 1); | ||
706 | |||
707 | /* ... and the PWR_INT module ... */ | ||
708 | status = twl4030_sih_setup(TWL4030_MODULE_INT); | ||
709 | if (status < 0) { | ||
710 | pr_err("twl4030: sih_setup PWR INT --> %d\n", status); | ||
711 | goto fail; | ||
712 | } | ||
713 | |||
714 | /* install an irq handler to demultiplex the TWL4030 interrupt */ | ||
715 | task = start_twl4030_irq_thread(irq_num); | ||
716 | if (!task) { | ||
717 | pr_err("twl4030: irq thread FAIL\n"); | ||
718 | status = -ESRCH; | ||
719 | goto fail; | ||
720 | } | ||
721 | |||
722 | set_irq_data(irq_num, task); | ||
723 | set_irq_chained_handler(irq_num, handle_twl4030_pih); | ||
724 | |||
725 | return status; | ||
726 | |||
727 | fail: | ||
728 | for (i = irq_base; i < irq_end; i++) | ||
729 | set_irq_chip_and_handler(i, NULL, NULL); | ||
730 | destroy_workqueue(wq); | ||
731 | wq = NULL; | ||
732 | return status; | ||
733 | } | ||
734 | |||
735 | int twl_exit_irq(void) | ||
736 | { | ||
737 | /* FIXME undo twl_init_irq() */ | ||
738 | if (twl4030_irq_base) { | ||
739 | pr_err("twl4030: can't yet clean up IRQs?\n"); | ||
740 | return -ENOSYS; | ||
741 | } | ||
742 | return 0; | ||
743 | } | ||
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c new file mode 100644 index 000000000000..178159e264ce --- /dev/null +++ b/drivers/mfd/ucb1400_core.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Core functions for: | ||
3 | * Philips UCB1400 multifunction chip | ||
4 | * | ||
5 | * Based on ucb1400_ts.c: | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: September 25, 2006 | ||
8 | * Copyright: MontaVista Software, Inc. | ||
9 | * | ||
10 | * Spliting done by: Marek Vasut <marek.vasut@gmail.com> | ||
11 | * If something doesnt work and it worked before spliting, e-mail me, | ||
12 | * dont bother Nicolas please ;-) | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | * | ||
18 | * This code is heavily based on ucb1x00-*.c copyrighted by Russell King | ||
19 | * covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has | ||
20 | * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/ucb1400.h> | ||
25 | |||
26 | static int ucb1400_core_probe(struct device *dev) | ||
27 | { | ||
28 | int err; | ||
29 | struct ucb1400 *ucb; | ||
30 | struct ucb1400_ts ucb_ts; | ||
31 | struct snd_ac97 *ac97; | ||
32 | |||
33 | memset(&ucb_ts, 0, sizeof(ucb_ts)); | ||
34 | |||
35 | ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL); | ||
36 | if (!ucb) { | ||
37 | err = -ENOMEM; | ||
38 | goto err; | ||
39 | } | ||
40 | |||
41 | dev_set_drvdata(dev, ucb); | ||
42 | |||
43 | ac97 = to_ac97_t(dev); | ||
44 | |||
45 | ucb_ts.id = ucb1400_reg_read(ac97, UCB_ID); | ||
46 | if (ucb_ts.id != UCB_ID_1400) { | ||
47 | err = -ENODEV; | ||
48 | goto err0; | ||
49 | } | ||
50 | |||
51 | /* TOUCHSCREEN */ | ||
52 | ucb_ts.ac97 = ac97; | ||
53 | ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1); | ||
54 | if (!ucb->ucb1400_ts) { | ||
55 | err = -ENOMEM; | ||
56 | goto err0; | ||
57 | } | ||
58 | err = platform_device_add_data(ucb->ucb1400_ts, &ucb_ts, | ||
59 | sizeof(ucb_ts)); | ||
60 | if (err) | ||
61 | goto err1; | ||
62 | err = platform_device_add(ucb->ucb1400_ts); | ||
63 | if (err) | ||
64 | goto err1; | ||
65 | |||
66 | return 0; | ||
67 | |||
68 | err1: | ||
69 | platform_device_put(ucb->ucb1400_ts); | ||
70 | err0: | ||
71 | kfree(ucb); | ||
72 | err: | ||
73 | return err; | ||
74 | } | ||
75 | |||
76 | static int ucb1400_core_remove(struct device *dev) | ||
77 | { | ||
78 | struct ucb1400 *ucb = dev_get_drvdata(dev); | ||
79 | |||
80 | platform_device_unregister(ucb->ucb1400_ts); | ||
81 | kfree(ucb); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static struct device_driver ucb1400_core_driver = { | ||
86 | .name = "ucb1400_core", | ||
87 | .bus = &ac97_bus_type, | ||
88 | .probe = ucb1400_core_probe, | ||
89 | .remove = ucb1400_core_remove, | ||
90 | }; | ||
91 | |||
92 | static int __init ucb1400_core_init(void) | ||
93 | { | ||
94 | return driver_register(&ucb1400_core_driver); | ||
95 | } | ||
96 | |||
97 | static void __exit ucb1400_core_exit(void) | ||
98 | { | ||
99 | driver_unregister(&ucb1400_core_driver); | ||
100 | } | ||
101 | |||
102 | module_init(ucb1400_core_init); | ||
103 | module_exit(ucb1400_core_exit); | ||
104 | |||
105 | MODULE_DESCRIPTION("Philips UCB1400 driver"); | ||
106 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index f6b10dda31fd..a316f1b75933 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
27 | 27 | ||
28 | #include <asm/dma.h> | 28 | #include <asm/dma.h> |
29 | #include <asm/hardware.h> | 29 | #include <mach/hardware.h> |
30 | 30 | ||
31 | #include "ucb1x00.h" | 31 | #include "ucb1x00.h" |
32 | 32 | ||
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index ad34e2d22524..44762ca86a8d 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/kthread.h> | 32 | #include <linux/kthread.h> |
33 | 33 | ||
34 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
35 | #include <asm/arch/collie.h> | 35 | #include <mach/collie.h> |
36 | #include <asm/mach-types.h> | 36 | #include <asm/mach-types.h> |
37 | 37 | ||
38 | #include "ucb1x00.h" | 38 | #include "ucb1x00.h" |
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c new file mode 100644 index 000000000000..0d47fb9e4b3b --- /dev/null +++ b/drivers/mfd/wm8350-core.c | |||
@@ -0,0 +1,1276 @@ | |||
1 | /* | ||
2 | * wm8350-core.c -- Device access for Wolfson WM8350 | ||
3 | * | ||
4 | * Copyright 2007, 2008 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Liam Girdwood, Mark Brown | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/bug.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/workqueue.h> | ||
23 | |||
24 | #include <linux/mfd/wm8350/core.h> | ||
25 | #include <linux/mfd/wm8350/audio.h> | ||
26 | #include <linux/mfd/wm8350/comparator.h> | ||
27 | #include <linux/mfd/wm8350/gpio.h> | ||
28 | #include <linux/mfd/wm8350/pmic.h> | ||
29 | #include <linux/mfd/wm8350/rtc.h> | ||
30 | #include <linux/mfd/wm8350/supply.h> | ||
31 | #include <linux/mfd/wm8350/wdt.h> | ||
32 | |||
33 | #define WM8350_UNLOCK_KEY 0x0013 | ||
34 | #define WM8350_LOCK_KEY 0x0000 | ||
35 | |||
36 | #define WM8350_CLOCK_CONTROL_1 0x28 | ||
37 | #define WM8350_AIF_TEST 0x74 | ||
38 | |||
39 | /* debug */ | ||
40 | #define WM8350_BUS_DEBUG 0 | ||
41 | #if WM8350_BUS_DEBUG | ||
42 | #define dump(regs, src) do { \ | ||
43 | int i_; \ | ||
44 | u16 *src_ = src; \ | ||
45 | printk(KERN_DEBUG); \ | ||
46 | for (i_ = 0; i_ < regs; i_++) \ | ||
47 | printk(" 0x%4.4x", *src_++); \ | ||
48 | printk("\n"); \ | ||
49 | } while (0); | ||
50 | #else | ||
51 | #define dump(bytes, src) | ||
52 | #endif | ||
53 | |||
54 | #define WM8350_LOCK_DEBUG 0 | ||
55 | #if WM8350_LOCK_DEBUG | ||
56 | #define ldbg(format, arg...) printk(format, ## arg) | ||
57 | #else | ||
58 | #define ldbg(format, arg...) | ||
59 | #endif | ||
60 | |||
61 | /* | ||
62 | * WM8350 Device IO | ||
63 | */ | ||
64 | static DEFINE_MUTEX(io_mutex); | ||
65 | static DEFINE_MUTEX(reg_lock_mutex); | ||
66 | static DEFINE_MUTEX(auxadc_mutex); | ||
67 | |||
68 | /* Perform a physical read from the device. | ||
69 | */ | ||
70 | static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs, | ||
71 | u16 *dest) | ||
72 | { | ||
73 | int i, ret; | ||
74 | int bytes = num_regs * 2; | ||
75 | |||
76 | dev_dbg(wm8350->dev, "volatile read\n"); | ||
77 | ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest); | ||
78 | |||
79 | for (i = reg; i < reg + num_regs; i++) { | ||
80 | /* Cache is CPU endian */ | ||
81 | dest[i - reg] = be16_to_cpu(dest[i - reg]); | ||
82 | |||
83 | /* Satisfy non-volatile bits from cache */ | ||
84 | dest[i - reg] &= wm8350_reg_io_map[i].vol; | ||
85 | dest[i - reg] |= wm8350->reg_cache[i]; | ||
86 | |||
87 | /* Mask out non-readable bits */ | ||
88 | dest[i - reg] &= wm8350_reg_io_map[i].readable; | ||
89 | } | ||
90 | |||
91 | dump(num_regs, dest); | ||
92 | |||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest) | ||
97 | { | ||
98 | int i; | ||
99 | int end = reg + num_regs; | ||
100 | int ret = 0; | ||
101 | int bytes = num_regs * 2; | ||
102 | |||
103 | if (wm8350->read_dev == NULL) | ||
104 | return -ENODEV; | ||
105 | |||
106 | if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) { | ||
107 | dev_err(wm8350->dev, "invalid reg %x\n", | ||
108 | reg + num_regs - 1); | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | |||
112 | dev_dbg(wm8350->dev, | ||
113 | "%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs); | ||
114 | |||
115 | #if WM8350_BUS_DEBUG | ||
116 | /* we can _safely_ read any register, but warn if read not supported */ | ||
117 | for (i = reg; i < end; i++) { | ||
118 | if (!wm8350_reg_io_map[i].readable) | ||
119 | dev_warn(wm8350->dev, | ||
120 | "reg R%d is not readable\n", i); | ||
121 | } | ||
122 | #endif | ||
123 | |||
124 | /* if any volatile registers are required, then read back all */ | ||
125 | for (i = reg; i < end; i++) | ||
126 | if (wm8350_reg_io_map[i].vol) | ||
127 | return wm8350_phys_read(wm8350, reg, num_regs, dest); | ||
128 | |||
129 | /* no volatiles, then cache is good */ | ||
130 | dev_dbg(wm8350->dev, "cache read\n"); | ||
131 | memcpy(dest, &wm8350->reg_cache[reg], bytes); | ||
132 | dump(num_regs, dest); | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg) | ||
137 | { | ||
138 | if (reg == WM8350_SECURITY || | ||
139 | wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY) | ||
140 | return 0; | ||
141 | |||
142 | if ((reg == WM8350_GPIO_CONFIGURATION_I_O) || | ||
143 | (reg >= WM8350_GPIO_FUNCTION_SELECT_1 && | ||
144 | reg <= WM8350_GPIO_FUNCTION_SELECT_4) || | ||
145 | (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 && | ||
146 | reg <= WM8350_BATTERY_CHARGER_CONTROL_3)) | ||
147 | return 1; | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src) | ||
152 | { | ||
153 | int i; | ||
154 | int end = reg + num_regs; | ||
155 | int bytes = num_regs * 2; | ||
156 | |||
157 | if (wm8350->write_dev == NULL) | ||
158 | return -ENODEV; | ||
159 | |||
160 | if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) { | ||
161 | dev_err(wm8350->dev, "invalid reg %x\n", | ||
162 | reg + num_regs - 1); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | /* it's generally not a good idea to write to RO or locked registers */ | ||
167 | for (i = reg; i < end; i++) { | ||
168 | if (!wm8350_reg_io_map[i].writable) { | ||
169 | dev_err(wm8350->dev, | ||
170 | "attempted write to read only reg R%d\n", i); | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | if (is_reg_locked(wm8350, i)) { | ||
175 | dev_err(wm8350->dev, | ||
176 | "attempted write to locked reg R%d\n", i); | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | |||
180 | src[i - reg] &= wm8350_reg_io_map[i].writable; | ||
181 | |||
182 | wm8350->reg_cache[i] = | ||
183 | (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable) | ||
184 | | src[i - reg]; | ||
185 | |||
186 | /* Don't store volatile bits */ | ||
187 | wm8350->reg_cache[i] &= ~wm8350_reg_io_map[i].vol; | ||
188 | |||
189 | src[i - reg] = cpu_to_be16(src[i - reg]); | ||
190 | } | ||
191 | |||
192 | /* Actually write it out */ | ||
193 | return wm8350->write_dev(wm8350, reg, bytes, (char *)src); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Safe read, modify, write methods | ||
198 | */ | ||
199 | int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask) | ||
200 | { | ||
201 | u16 data; | ||
202 | int err; | ||
203 | |||
204 | mutex_lock(&io_mutex); | ||
205 | err = wm8350_read(wm8350, reg, 1, &data); | ||
206 | if (err) { | ||
207 | dev_err(wm8350->dev, "read from reg R%d failed\n", reg); | ||
208 | goto out; | ||
209 | } | ||
210 | |||
211 | data &= ~mask; | ||
212 | err = wm8350_write(wm8350, reg, 1, &data); | ||
213 | if (err) | ||
214 | dev_err(wm8350->dev, "write to reg R%d failed\n", reg); | ||
215 | out: | ||
216 | mutex_unlock(&io_mutex); | ||
217 | return err; | ||
218 | } | ||
219 | EXPORT_SYMBOL_GPL(wm8350_clear_bits); | ||
220 | |||
221 | int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask) | ||
222 | { | ||
223 | u16 data; | ||
224 | int err; | ||
225 | |||
226 | mutex_lock(&io_mutex); | ||
227 | err = wm8350_read(wm8350, reg, 1, &data); | ||
228 | if (err) { | ||
229 | dev_err(wm8350->dev, "read from reg R%d failed\n", reg); | ||
230 | goto out; | ||
231 | } | ||
232 | |||
233 | data |= mask; | ||
234 | err = wm8350_write(wm8350, reg, 1, &data); | ||
235 | if (err) | ||
236 | dev_err(wm8350->dev, "write to reg R%d failed\n", reg); | ||
237 | out: | ||
238 | mutex_unlock(&io_mutex); | ||
239 | return err; | ||
240 | } | ||
241 | EXPORT_SYMBOL_GPL(wm8350_set_bits); | ||
242 | |||
243 | u16 wm8350_reg_read(struct wm8350 *wm8350, int reg) | ||
244 | { | ||
245 | u16 data; | ||
246 | int err; | ||
247 | |||
248 | mutex_lock(&io_mutex); | ||
249 | err = wm8350_read(wm8350, reg, 1, &data); | ||
250 | if (err) | ||
251 | dev_err(wm8350->dev, "read from reg R%d failed\n", reg); | ||
252 | |||
253 | mutex_unlock(&io_mutex); | ||
254 | return data; | ||
255 | } | ||
256 | EXPORT_SYMBOL_GPL(wm8350_reg_read); | ||
257 | |||
258 | int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val) | ||
259 | { | ||
260 | int ret; | ||
261 | u16 data = val; | ||
262 | |||
263 | mutex_lock(&io_mutex); | ||
264 | ret = wm8350_write(wm8350, reg, 1, &data); | ||
265 | if (ret) | ||
266 | dev_err(wm8350->dev, "write to reg R%d failed\n", reg); | ||
267 | mutex_unlock(&io_mutex); | ||
268 | return ret; | ||
269 | } | ||
270 | EXPORT_SYMBOL_GPL(wm8350_reg_write); | ||
271 | |||
272 | int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs, | ||
273 | u16 *dest) | ||
274 | { | ||
275 | int err = 0; | ||
276 | |||
277 | mutex_lock(&io_mutex); | ||
278 | err = wm8350_read(wm8350, start_reg, regs, dest); | ||
279 | if (err) | ||
280 | dev_err(wm8350->dev, "block read starting from R%d failed\n", | ||
281 | start_reg); | ||
282 | mutex_unlock(&io_mutex); | ||
283 | return err; | ||
284 | } | ||
285 | EXPORT_SYMBOL_GPL(wm8350_block_read); | ||
286 | |||
287 | int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs, | ||
288 | u16 *src) | ||
289 | { | ||
290 | int ret = 0; | ||
291 | |||
292 | mutex_lock(&io_mutex); | ||
293 | ret = wm8350_write(wm8350, start_reg, regs, src); | ||
294 | if (ret) | ||
295 | dev_err(wm8350->dev, "block write starting at R%d failed\n", | ||
296 | start_reg); | ||
297 | mutex_unlock(&io_mutex); | ||
298 | return ret; | ||
299 | } | ||
300 | EXPORT_SYMBOL_GPL(wm8350_block_write); | ||
301 | |||
302 | int wm8350_reg_lock(struct wm8350 *wm8350) | ||
303 | { | ||
304 | u16 key = WM8350_LOCK_KEY; | ||
305 | int ret; | ||
306 | |||
307 | ldbg(__func__); | ||
308 | mutex_lock(&io_mutex); | ||
309 | ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key); | ||
310 | if (ret) | ||
311 | dev_err(wm8350->dev, "lock failed\n"); | ||
312 | mutex_unlock(&io_mutex); | ||
313 | return ret; | ||
314 | } | ||
315 | EXPORT_SYMBOL_GPL(wm8350_reg_lock); | ||
316 | |||
317 | int wm8350_reg_unlock(struct wm8350 *wm8350) | ||
318 | { | ||
319 | u16 key = WM8350_UNLOCK_KEY; | ||
320 | int ret; | ||
321 | |||
322 | ldbg(__func__); | ||
323 | mutex_lock(&io_mutex); | ||
324 | ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key); | ||
325 | if (ret) | ||
326 | dev_err(wm8350->dev, "unlock failed\n"); | ||
327 | mutex_unlock(&io_mutex); | ||
328 | return ret; | ||
329 | } | ||
330 | EXPORT_SYMBOL_GPL(wm8350_reg_unlock); | ||
331 | |||
332 | static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) | ||
333 | { | ||
334 | mutex_lock(&wm8350->irq_mutex); | ||
335 | |||
336 | if (wm8350->irq[irq].handler) | ||
337 | wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data); | ||
338 | else { | ||
339 | dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", | ||
340 | irq); | ||
341 | wm8350_mask_irq(wm8350, irq); | ||
342 | } | ||
343 | |||
344 | mutex_unlock(&wm8350->irq_mutex); | ||
345 | } | ||
346 | |||
347 | /* | ||
348 | * wm8350_irq_worker actually handles the interrupts. Since all | ||
349 | * interrupts are clear on read the IRQ line will be reasserted and | ||
350 | * the physical IRQ will be handled again if another interrupt is | ||
351 | * asserted while we run - in the normal course of events this is a | ||
352 | * rare occurrence so we save I2C/SPI reads. | ||
353 | */ | ||
354 | static void wm8350_irq_worker(struct work_struct *work) | ||
355 | { | ||
356 | struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work); | ||
357 | u16 level_one, status1, status2, comp; | ||
358 | |||
359 | /* TODO: Use block reads to improve performance? */ | ||
360 | level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) | ||
361 | & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); | ||
362 | status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1) | ||
363 | & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK); | ||
364 | status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2) | ||
365 | & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK); | ||
366 | comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS) | ||
367 | & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK); | ||
368 | |||
369 | /* over current */ | ||
370 | if (level_one & WM8350_OC_INT) { | ||
371 | u16 oc; | ||
372 | |||
373 | oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS); | ||
374 | oc &= ~wm8350_reg_read(wm8350, | ||
375 | WM8350_OVER_CURRENT_INT_STATUS_MASK); | ||
376 | |||
377 | if (oc & WM8350_OC_LS_EINT) /* limit switch */ | ||
378 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS); | ||
379 | } | ||
380 | |||
381 | /* under voltage */ | ||
382 | if (level_one & WM8350_UV_INT) { | ||
383 | u16 uv; | ||
384 | |||
385 | uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS); | ||
386 | uv &= ~wm8350_reg_read(wm8350, | ||
387 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK); | ||
388 | |||
389 | if (uv & WM8350_UV_DC1_EINT) | ||
390 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1); | ||
391 | if (uv & WM8350_UV_DC2_EINT) | ||
392 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2); | ||
393 | if (uv & WM8350_UV_DC3_EINT) | ||
394 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3); | ||
395 | if (uv & WM8350_UV_DC4_EINT) | ||
396 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4); | ||
397 | if (uv & WM8350_UV_DC5_EINT) | ||
398 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5); | ||
399 | if (uv & WM8350_UV_DC6_EINT) | ||
400 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6); | ||
401 | if (uv & WM8350_UV_LDO1_EINT) | ||
402 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1); | ||
403 | if (uv & WM8350_UV_LDO2_EINT) | ||
404 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2); | ||
405 | if (uv & WM8350_UV_LDO3_EINT) | ||
406 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3); | ||
407 | if (uv & WM8350_UV_LDO4_EINT) | ||
408 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4); | ||
409 | } | ||
410 | |||
411 | /* charger, RTC */ | ||
412 | if (status1) { | ||
413 | if (status1 & WM8350_CHG_BAT_HOT_EINT) | ||
414 | wm8350_irq_call_handler(wm8350, | ||
415 | WM8350_IRQ_CHG_BAT_HOT); | ||
416 | if (status1 & WM8350_CHG_BAT_COLD_EINT) | ||
417 | wm8350_irq_call_handler(wm8350, | ||
418 | WM8350_IRQ_CHG_BAT_COLD); | ||
419 | if (status1 & WM8350_CHG_BAT_FAIL_EINT) | ||
420 | wm8350_irq_call_handler(wm8350, | ||
421 | WM8350_IRQ_CHG_BAT_FAIL); | ||
422 | if (status1 & WM8350_CHG_TO_EINT) | ||
423 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO); | ||
424 | if (status1 & WM8350_CHG_END_EINT) | ||
425 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END); | ||
426 | if (status1 & WM8350_CHG_START_EINT) | ||
427 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START); | ||
428 | if (status1 & WM8350_CHG_FAST_RDY_EINT) | ||
429 | wm8350_irq_call_handler(wm8350, | ||
430 | WM8350_IRQ_CHG_FAST_RDY); | ||
431 | if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT) | ||
432 | wm8350_irq_call_handler(wm8350, | ||
433 | WM8350_IRQ_CHG_VBATT_LT_3P9); | ||
434 | if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT) | ||
435 | wm8350_irq_call_handler(wm8350, | ||
436 | WM8350_IRQ_CHG_VBATT_LT_3P1); | ||
437 | if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT) | ||
438 | wm8350_irq_call_handler(wm8350, | ||
439 | WM8350_IRQ_CHG_VBATT_LT_2P85); | ||
440 | if (status1 & WM8350_RTC_ALM_EINT) | ||
441 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM); | ||
442 | if (status1 & WM8350_RTC_SEC_EINT) | ||
443 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC); | ||
444 | if (status1 & WM8350_RTC_PER_EINT) | ||
445 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER); | ||
446 | } | ||
447 | |||
448 | /* current sink, system, aux adc */ | ||
449 | if (status2) { | ||
450 | if (status2 & WM8350_CS1_EINT) | ||
451 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1); | ||
452 | if (status2 & WM8350_CS2_EINT) | ||
453 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2); | ||
454 | |||
455 | if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT) | ||
456 | wm8350_irq_call_handler(wm8350, | ||
457 | WM8350_IRQ_SYS_HYST_COMP_FAIL); | ||
458 | if (status2 & WM8350_SYS_CHIP_GT115_EINT) | ||
459 | wm8350_irq_call_handler(wm8350, | ||
460 | WM8350_IRQ_SYS_CHIP_GT115); | ||
461 | if (status2 & WM8350_SYS_CHIP_GT140_EINT) | ||
462 | wm8350_irq_call_handler(wm8350, | ||
463 | WM8350_IRQ_SYS_CHIP_GT140); | ||
464 | if (status2 & WM8350_SYS_WDOG_TO_EINT) | ||
465 | wm8350_irq_call_handler(wm8350, | ||
466 | WM8350_IRQ_SYS_WDOG_TO); | ||
467 | |||
468 | if (status2 & WM8350_AUXADC_DATARDY_EINT) | ||
469 | wm8350_irq_call_handler(wm8350, | ||
470 | WM8350_IRQ_AUXADC_DATARDY); | ||
471 | if (status2 & WM8350_AUXADC_DCOMP4_EINT) | ||
472 | wm8350_irq_call_handler(wm8350, | ||
473 | WM8350_IRQ_AUXADC_DCOMP4); | ||
474 | if (status2 & WM8350_AUXADC_DCOMP3_EINT) | ||
475 | wm8350_irq_call_handler(wm8350, | ||
476 | WM8350_IRQ_AUXADC_DCOMP3); | ||
477 | if (status2 & WM8350_AUXADC_DCOMP2_EINT) | ||
478 | wm8350_irq_call_handler(wm8350, | ||
479 | WM8350_IRQ_AUXADC_DCOMP2); | ||
480 | if (status2 & WM8350_AUXADC_DCOMP1_EINT) | ||
481 | wm8350_irq_call_handler(wm8350, | ||
482 | WM8350_IRQ_AUXADC_DCOMP1); | ||
483 | |||
484 | if (status2 & WM8350_USB_LIMIT_EINT) | ||
485 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT); | ||
486 | } | ||
487 | |||
488 | /* wake, codec, ext */ | ||
489 | if (comp) { | ||
490 | if (comp & WM8350_WKUP_OFF_STATE_EINT) | ||
491 | wm8350_irq_call_handler(wm8350, | ||
492 | WM8350_IRQ_WKUP_OFF_STATE); | ||
493 | if (comp & WM8350_WKUP_HIB_STATE_EINT) | ||
494 | wm8350_irq_call_handler(wm8350, | ||
495 | WM8350_IRQ_WKUP_HIB_STATE); | ||
496 | if (comp & WM8350_WKUP_CONV_FAULT_EINT) | ||
497 | wm8350_irq_call_handler(wm8350, | ||
498 | WM8350_IRQ_WKUP_CONV_FAULT); | ||
499 | if (comp & WM8350_WKUP_WDOG_RST_EINT) | ||
500 | wm8350_irq_call_handler(wm8350, | ||
501 | WM8350_IRQ_WKUP_WDOG_RST); | ||
502 | if (comp & WM8350_WKUP_GP_PWR_ON_EINT) | ||
503 | wm8350_irq_call_handler(wm8350, | ||
504 | WM8350_IRQ_WKUP_GP_PWR_ON); | ||
505 | if (comp & WM8350_WKUP_ONKEY_EINT) | ||
506 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY); | ||
507 | if (comp & WM8350_WKUP_GP_WAKEUP_EINT) | ||
508 | wm8350_irq_call_handler(wm8350, | ||
509 | WM8350_IRQ_WKUP_GP_WAKEUP); | ||
510 | |||
511 | if (comp & WM8350_CODEC_JCK_DET_L_EINT) | ||
512 | wm8350_irq_call_handler(wm8350, | ||
513 | WM8350_IRQ_CODEC_JCK_DET_L); | ||
514 | if (comp & WM8350_CODEC_JCK_DET_R_EINT) | ||
515 | wm8350_irq_call_handler(wm8350, | ||
516 | WM8350_IRQ_CODEC_JCK_DET_R); | ||
517 | if (comp & WM8350_CODEC_MICSCD_EINT) | ||
518 | wm8350_irq_call_handler(wm8350, | ||
519 | WM8350_IRQ_CODEC_MICSCD); | ||
520 | if (comp & WM8350_CODEC_MICD_EINT) | ||
521 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD); | ||
522 | |||
523 | if (comp & WM8350_EXT_USB_FB_EINT) | ||
524 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB); | ||
525 | if (comp & WM8350_EXT_WALL_FB_EINT) | ||
526 | wm8350_irq_call_handler(wm8350, | ||
527 | WM8350_IRQ_EXT_WALL_FB); | ||
528 | if (comp & WM8350_EXT_BAT_FB_EINT) | ||
529 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB); | ||
530 | } | ||
531 | |||
532 | if (level_one & WM8350_GP_INT) { | ||
533 | int i; | ||
534 | u16 gpio; | ||
535 | |||
536 | gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS); | ||
537 | gpio &= ~wm8350_reg_read(wm8350, | ||
538 | WM8350_GPIO_INT_STATUS_MASK); | ||
539 | |||
540 | for (i = 0; i < 12; i++) { | ||
541 | if (gpio & (1 << i)) | ||
542 | wm8350_irq_call_handler(wm8350, | ||
543 | WM8350_IRQ_GPIO(i)); | ||
544 | } | ||
545 | } | ||
546 | |||
547 | enable_irq(wm8350->chip_irq); | ||
548 | } | ||
549 | |||
550 | static irqreturn_t wm8350_irq(int irq, void *data) | ||
551 | { | ||
552 | struct wm8350 *wm8350 = data; | ||
553 | |||
554 | disable_irq_nosync(irq); | ||
555 | schedule_work(&wm8350->irq_work); | ||
556 | |||
557 | return IRQ_HANDLED; | ||
558 | } | ||
559 | |||
560 | int wm8350_register_irq(struct wm8350 *wm8350, int irq, | ||
561 | void (*handler) (struct wm8350 *, int, void *), | ||
562 | void *data) | ||
563 | { | ||
564 | if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) | ||
565 | return -EINVAL; | ||
566 | |||
567 | if (wm8350->irq[irq].handler) | ||
568 | return -EBUSY; | ||
569 | |||
570 | mutex_lock(&wm8350->irq_mutex); | ||
571 | wm8350->irq[irq].handler = handler; | ||
572 | wm8350->irq[irq].data = data; | ||
573 | mutex_unlock(&wm8350->irq_mutex); | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | EXPORT_SYMBOL_GPL(wm8350_register_irq); | ||
578 | |||
579 | int wm8350_free_irq(struct wm8350 *wm8350, int irq) | ||
580 | { | ||
581 | if (irq < 0 || irq > WM8350_NUM_IRQ) | ||
582 | return -EINVAL; | ||
583 | |||
584 | mutex_lock(&wm8350->irq_mutex); | ||
585 | wm8350->irq[irq].handler = NULL; | ||
586 | mutex_unlock(&wm8350->irq_mutex); | ||
587 | return 0; | ||
588 | } | ||
589 | EXPORT_SYMBOL_GPL(wm8350_free_irq); | ||
590 | |||
591 | int wm8350_mask_irq(struct wm8350 *wm8350, int irq) | ||
592 | { | ||
593 | switch (irq) { | ||
594 | case WM8350_IRQ_CHG_BAT_HOT: | ||
595 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
596 | WM8350_IM_CHG_BAT_HOT_EINT); | ||
597 | case WM8350_IRQ_CHG_BAT_COLD: | ||
598 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
599 | WM8350_IM_CHG_BAT_COLD_EINT); | ||
600 | case WM8350_IRQ_CHG_BAT_FAIL: | ||
601 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
602 | WM8350_IM_CHG_BAT_FAIL_EINT); | ||
603 | case WM8350_IRQ_CHG_TO: | ||
604 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
605 | WM8350_IM_CHG_TO_EINT); | ||
606 | case WM8350_IRQ_CHG_END: | ||
607 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
608 | WM8350_IM_CHG_END_EINT); | ||
609 | case WM8350_IRQ_CHG_START: | ||
610 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
611 | WM8350_IM_CHG_START_EINT); | ||
612 | case WM8350_IRQ_CHG_FAST_RDY: | ||
613 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
614 | WM8350_IM_CHG_FAST_RDY_EINT); | ||
615 | case WM8350_IRQ_RTC_PER: | ||
616 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
617 | WM8350_IM_RTC_PER_EINT); | ||
618 | case WM8350_IRQ_RTC_SEC: | ||
619 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
620 | WM8350_IM_RTC_SEC_EINT); | ||
621 | case WM8350_IRQ_RTC_ALM: | ||
622 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
623 | WM8350_IM_RTC_ALM_EINT); | ||
624 | case WM8350_IRQ_CHG_VBATT_LT_3P9: | ||
625 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
626 | WM8350_IM_CHG_VBATT_LT_3P9_EINT); | ||
627 | case WM8350_IRQ_CHG_VBATT_LT_3P1: | ||
628 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
629 | WM8350_IM_CHG_VBATT_LT_3P1_EINT); | ||
630 | case WM8350_IRQ_CHG_VBATT_LT_2P85: | ||
631 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
632 | WM8350_IM_CHG_VBATT_LT_2P85_EINT); | ||
633 | case WM8350_IRQ_CS1: | ||
634 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
635 | WM8350_IM_CS1_EINT); | ||
636 | case WM8350_IRQ_CS2: | ||
637 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
638 | WM8350_IM_CS2_EINT); | ||
639 | case WM8350_IRQ_USB_LIMIT: | ||
640 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
641 | WM8350_IM_USB_LIMIT_EINT); | ||
642 | case WM8350_IRQ_AUXADC_DATARDY: | ||
643 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
644 | WM8350_IM_AUXADC_DATARDY_EINT); | ||
645 | case WM8350_IRQ_AUXADC_DCOMP4: | ||
646 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
647 | WM8350_IM_AUXADC_DCOMP4_EINT); | ||
648 | case WM8350_IRQ_AUXADC_DCOMP3: | ||
649 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
650 | WM8350_IM_AUXADC_DCOMP3_EINT); | ||
651 | case WM8350_IRQ_AUXADC_DCOMP2: | ||
652 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
653 | WM8350_IM_AUXADC_DCOMP2_EINT); | ||
654 | case WM8350_IRQ_AUXADC_DCOMP1: | ||
655 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
656 | WM8350_IM_AUXADC_DCOMP1_EINT); | ||
657 | case WM8350_IRQ_SYS_HYST_COMP_FAIL: | ||
658 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
659 | WM8350_IM_SYS_HYST_COMP_FAIL_EINT); | ||
660 | case WM8350_IRQ_SYS_CHIP_GT115: | ||
661 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
662 | WM8350_IM_SYS_CHIP_GT115_EINT); | ||
663 | case WM8350_IRQ_SYS_CHIP_GT140: | ||
664 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
665 | WM8350_IM_SYS_CHIP_GT140_EINT); | ||
666 | case WM8350_IRQ_SYS_WDOG_TO: | ||
667 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
668 | WM8350_IM_SYS_WDOG_TO_EINT); | ||
669 | case WM8350_IRQ_UV_LDO4: | ||
670 | return wm8350_set_bits(wm8350, | ||
671 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
672 | WM8350_IM_UV_LDO4_EINT); | ||
673 | case WM8350_IRQ_UV_LDO3: | ||
674 | return wm8350_set_bits(wm8350, | ||
675 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
676 | WM8350_IM_UV_LDO3_EINT); | ||
677 | case WM8350_IRQ_UV_LDO2: | ||
678 | return wm8350_set_bits(wm8350, | ||
679 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
680 | WM8350_IM_UV_LDO2_EINT); | ||
681 | case WM8350_IRQ_UV_LDO1: | ||
682 | return wm8350_set_bits(wm8350, | ||
683 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
684 | WM8350_IM_UV_LDO1_EINT); | ||
685 | case WM8350_IRQ_UV_DC6: | ||
686 | return wm8350_set_bits(wm8350, | ||
687 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
688 | WM8350_IM_UV_DC6_EINT); | ||
689 | case WM8350_IRQ_UV_DC5: | ||
690 | return wm8350_set_bits(wm8350, | ||
691 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
692 | WM8350_IM_UV_DC5_EINT); | ||
693 | case WM8350_IRQ_UV_DC4: | ||
694 | return wm8350_set_bits(wm8350, | ||
695 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
696 | WM8350_IM_UV_DC4_EINT); | ||
697 | case WM8350_IRQ_UV_DC3: | ||
698 | return wm8350_set_bits(wm8350, | ||
699 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
700 | WM8350_IM_UV_DC3_EINT); | ||
701 | case WM8350_IRQ_UV_DC2: | ||
702 | return wm8350_set_bits(wm8350, | ||
703 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
704 | WM8350_IM_UV_DC2_EINT); | ||
705 | case WM8350_IRQ_UV_DC1: | ||
706 | return wm8350_set_bits(wm8350, | ||
707 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
708 | WM8350_IM_UV_DC1_EINT); | ||
709 | case WM8350_IRQ_OC_LS: | ||
710 | return wm8350_set_bits(wm8350, | ||
711 | WM8350_OVER_CURRENT_INT_STATUS_MASK, | ||
712 | WM8350_IM_OC_LS_EINT); | ||
713 | case WM8350_IRQ_EXT_USB_FB: | ||
714 | return wm8350_set_bits(wm8350, | ||
715 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
716 | WM8350_IM_EXT_USB_FB_EINT); | ||
717 | case WM8350_IRQ_EXT_WALL_FB: | ||
718 | return wm8350_set_bits(wm8350, | ||
719 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
720 | WM8350_IM_EXT_WALL_FB_EINT); | ||
721 | case WM8350_IRQ_EXT_BAT_FB: | ||
722 | return wm8350_set_bits(wm8350, | ||
723 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
724 | WM8350_IM_EXT_BAT_FB_EINT); | ||
725 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
726 | return wm8350_set_bits(wm8350, | ||
727 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
728 | WM8350_IM_CODEC_JCK_DET_L_EINT); | ||
729 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
730 | return wm8350_set_bits(wm8350, | ||
731 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
732 | WM8350_IM_CODEC_JCK_DET_R_EINT); | ||
733 | case WM8350_IRQ_CODEC_MICSCD: | ||
734 | return wm8350_set_bits(wm8350, | ||
735 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
736 | WM8350_IM_CODEC_MICSCD_EINT); | ||
737 | case WM8350_IRQ_CODEC_MICD: | ||
738 | return wm8350_set_bits(wm8350, | ||
739 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
740 | WM8350_IM_CODEC_MICD_EINT); | ||
741 | case WM8350_IRQ_WKUP_OFF_STATE: | ||
742 | return wm8350_set_bits(wm8350, | ||
743 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
744 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
745 | case WM8350_IRQ_WKUP_HIB_STATE: | ||
746 | return wm8350_set_bits(wm8350, | ||
747 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
748 | WM8350_IM_WKUP_HIB_STATE_EINT); | ||
749 | case WM8350_IRQ_WKUP_CONV_FAULT: | ||
750 | return wm8350_set_bits(wm8350, | ||
751 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
752 | WM8350_IM_WKUP_CONV_FAULT_EINT); | ||
753 | case WM8350_IRQ_WKUP_WDOG_RST: | ||
754 | return wm8350_set_bits(wm8350, | ||
755 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
756 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
757 | case WM8350_IRQ_WKUP_GP_PWR_ON: | ||
758 | return wm8350_set_bits(wm8350, | ||
759 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
760 | WM8350_IM_WKUP_GP_PWR_ON_EINT); | ||
761 | case WM8350_IRQ_WKUP_ONKEY: | ||
762 | return wm8350_set_bits(wm8350, | ||
763 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
764 | WM8350_IM_WKUP_ONKEY_EINT); | ||
765 | case WM8350_IRQ_WKUP_GP_WAKEUP: | ||
766 | return wm8350_set_bits(wm8350, | ||
767 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
768 | WM8350_IM_WKUP_GP_WAKEUP_EINT); | ||
769 | case WM8350_IRQ_GPIO(0): | ||
770 | return wm8350_set_bits(wm8350, | ||
771 | WM8350_GPIO_INT_STATUS_MASK, | ||
772 | WM8350_IM_GP0_EINT); | ||
773 | case WM8350_IRQ_GPIO(1): | ||
774 | return wm8350_set_bits(wm8350, | ||
775 | WM8350_GPIO_INT_STATUS_MASK, | ||
776 | WM8350_IM_GP1_EINT); | ||
777 | case WM8350_IRQ_GPIO(2): | ||
778 | return wm8350_set_bits(wm8350, | ||
779 | WM8350_GPIO_INT_STATUS_MASK, | ||
780 | WM8350_IM_GP2_EINT); | ||
781 | case WM8350_IRQ_GPIO(3): | ||
782 | return wm8350_set_bits(wm8350, | ||
783 | WM8350_GPIO_INT_STATUS_MASK, | ||
784 | WM8350_IM_GP3_EINT); | ||
785 | case WM8350_IRQ_GPIO(4): | ||
786 | return wm8350_set_bits(wm8350, | ||
787 | WM8350_GPIO_INT_STATUS_MASK, | ||
788 | WM8350_IM_GP4_EINT); | ||
789 | case WM8350_IRQ_GPIO(5): | ||
790 | return wm8350_set_bits(wm8350, | ||
791 | WM8350_GPIO_INT_STATUS_MASK, | ||
792 | WM8350_IM_GP5_EINT); | ||
793 | case WM8350_IRQ_GPIO(6): | ||
794 | return wm8350_set_bits(wm8350, | ||
795 | WM8350_GPIO_INT_STATUS_MASK, | ||
796 | WM8350_IM_GP6_EINT); | ||
797 | case WM8350_IRQ_GPIO(7): | ||
798 | return wm8350_set_bits(wm8350, | ||
799 | WM8350_GPIO_INT_STATUS_MASK, | ||
800 | WM8350_IM_GP7_EINT); | ||
801 | case WM8350_IRQ_GPIO(8): | ||
802 | return wm8350_set_bits(wm8350, | ||
803 | WM8350_GPIO_INT_STATUS_MASK, | ||
804 | WM8350_IM_GP8_EINT); | ||
805 | case WM8350_IRQ_GPIO(9): | ||
806 | return wm8350_set_bits(wm8350, | ||
807 | WM8350_GPIO_INT_STATUS_MASK, | ||
808 | WM8350_IM_GP9_EINT); | ||
809 | case WM8350_IRQ_GPIO(10): | ||
810 | return wm8350_set_bits(wm8350, | ||
811 | WM8350_GPIO_INT_STATUS_MASK, | ||
812 | WM8350_IM_GP10_EINT); | ||
813 | case WM8350_IRQ_GPIO(11): | ||
814 | return wm8350_set_bits(wm8350, | ||
815 | WM8350_GPIO_INT_STATUS_MASK, | ||
816 | WM8350_IM_GP11_EINT); | ||
817 | case WM8350_IRQ_GPIO(12): | ||
818 | return wm8350_set_bits(wm8350, | ||
819 | WM8350_GPIO_INT_STATUS_MASK, | ||
820 | WM8350_IM_GP12_EINT); | ||
821 | default: | ||
822 | dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n", | ||
823 | irq); | ||
824 | return -EINVAL; | ||
825 | } | ||
826 | return 0; | ||
827 | } | ||
828 | EXPORT_SYMBOL_GPL(wm8350_mask_irq); | ||
829 | |||
830 | int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) | ||
831 | { | ||
832 | switch (irq) { | ||
833 | case WM8350_IRQ_CHG_BAT_HOT: | ||
834 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
835 | WM8350_IM_CHG_BAT_HOT_EINT); | ||
836 | case WM8350_IRQ_CHG_BAT_COLD: | ||
837 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
838 | WM8350_IM_CHG_BAT_COLD_EINT); | ||
839 | case WM8350_IRQ_CHG_BAT_FAIL: | ||
840 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
841 | WM8350_IM_CHG_BAT_FAIL_EINT); | ||
842 | case WM8350_IRQ_CHG_TO: | ||
843 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
844 | WM8350_IM_CHG_TO_EINT); | ||
845 | case WM8350_IRQ_CHG_END: | ||
846 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
847 | WM8350_IM_CHG_END_EINT); | ||
848 | case WM8350_IRQ_CHG_START: | ||
849 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
850 | WM8350_IM_CHG_START_EINT); | ||
851 | case WM8350_IRQ_CHG_FAST_RDY: | ||
852 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
853 | WM8350_IM_CHG_FAST_RDY_EINT); | ||
854 | case WM8350_IRQ_RTC_PER: | ||
855 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
856 | WM8350_IM_RTC_PER_EINT); | ||
857 | case WM8350_IRQ_RTC_SEC: | ||
858 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
859 | WM8350_IM_RTC_SEC_EINT); | ||
860 | case WM8350_IRQ_RTC_ALM: | ||
861 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
862 | WM8350_IM_RTC_ALM_EINT); | ||
863 | case WM8350_IRQ_CHG_VBATT_LT_3P9: | ||
864 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
865 | WM8350_IM_CHG_VBATT_LT_3P9_EINT); | ||
866 | case WM8350_IRQ_CHG_VBATT_LT_3P1: | ||
867 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
868 | WM8350_IM_CHG_VBATT_LT_3P1_EINT); | ||
869 | case WM8350_IRQ_CHG_VBATT_LT_2P85: | ||
870 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
871 | WM8350_IM_CHG_VBATT_LT_2P85_EINT); | ||
872 | case WM8350_IRQ_CS1: | ||
873 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
874 | WM8350_IM_CS1_EINT); | ||
875 | case WM8350_IRQ_CS2: | ||
876 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
877 | WM8350_IM_CS2_EINT); | ||
878 | case WM8350_IRQ_USB_LIMIT: | ||
879 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
880 | WM8350_IM_USB_LIMIT_EINT); | ||
881 | case WM8350_IRQ_AUXADC_DATARDY: | ||
882 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
883 | WM8350_IM_AUXADC_DATARDY_EINT); | ||
884 | case WM8350_IRQ_AUXADC_DCOMP4: | ||
885 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
886 | WM8350_IM_AUXADC_DCOMP4_EINT); | ||
887 | case WM8350_IRQ_AUXADC_DCOMP3: | ||
888 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
889 | WM8350_IM_AUXADC_DCOMP3_EINT); | ||
890 | case WM8350_IRQ_AUXADC_DCOMP2: | ||
891 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
892 | WM8350_IM_AUXADC_DCOMP2_EINT); | ||
893 | case WM8350_IRQ_AUXADC_DCOMP1: | ||
894 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
895 | WM8350_IM_AUXADC_DCOMP1_EINT); | ||
896 | case WM8350_IRQ_SYS_HYST_COMP_FAIL: | ||
897 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
898 | WM8350_IM_SYS_HYST_COMP_FAIL_EINT); | ||
899 | case WM8350_IRQ_SYS_CHIP_GT115: | ||
900 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
901 | WM8350_IM_SYS_CHIP_GT115_EINT); | ||
902 | case WM8350_IRQ_SYS_CHIP_GT140: | ||
903 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
904 | WM8350_IM_SYS_CHIP_GT140_EINT); | ||
905 | case WM8350_IRQ_SYS_WDOG_TO: | ||
906 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
907 | WM8350_IM_SYS_WDOG_TO_EINT); | ||
908 | case WM8350_IRQ_UV_LDO4: | ||
909 | return wm8350_clear_bits(wm8350, | ||
910 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
911 | WM8350_IM_UV_LDO4_EINT); | ||
912 | case WM8350_IRQ_UV_LDO3: | ||
913 | return wm8350_clear_bits(wm8350, | ||
914 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
915 | WM8350_IM_UV_LDO3_EINT); | ||
916 | case WM8350_IRQ_UV_LDO2: | ||
917 | return wm8350_clear_bits(wm8350, | ||
918 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
919 | WM8350_IM_UV_LDO2_EINT); | ||
920 | case WM8350_IRQ_UV_LDO1: | ||
921 | return wm8350_clear_bits(wm8350, | ||
922 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
923 | WM8350_IM_UV_LDO1_EINT); | ||
924 | case WM8350_IRQ_UV_DC6: | ||
925 | return wm8350_clear_bits(wm8350, | ||
926 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
927 | WM8350_IM_UV_DC6_EINT); | ||
928 | case WM8350_IRQ_UV_DC5: | ||
929 | return wm8350_clear_bits(wm8350, | ||
930 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
931 | WM8350_IM_UV_DC5_EINT); | ||
932 | case WM8350_IRQ_UV_DC4: | ||
933 | return wm8350_clear_bits(wm8350, | ||
934 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
935 | WM8350_IM_UV_DC4_EINT); | ||
936 | case WM8350_IRQ_UV_DC3: | ||
937 | return wm8350_clear_bits(wm8350, | ||
938 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
939 | WM8350_IM_UV_DC3_EINT); | ||
940 | case WM8350_IRQ_UV_DC2: | ||
941 | return wm8350_clear_bits(wm8350, | ||
942 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
943 | WM8350_IM_UV_DC2_EINT); | ||
944 | case WM8350_IRQ_UV_DC1: | ||
945 | return wm8350_clear_bits(wm8350, | ||
946 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
947 | WM8350_IM_UV_DC1_EINT); | ||
948 | case WM8350_IRQ_OC_LS: | ||
949 | return wm8350_clear_bits(wm8350, | ||
950 | WM8350_OVER_CURRENT_INT_STATUS_MASK, | ||
951 | WM8350_IM_OC_LS_EINT); | ||
952 | case WM8350_IRQ_EXT_USB_FB: | ||
953 | return wm8350_clear_bits(wm8350, | ||
954 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
955 | WM8350_IM_EXT_USB_FB_EINT); | ||
956 | case WM8350_IRQ_EXT_WALL_FB: | ||
957 | return wm8350_clear_bits(wm8350, | ||
958 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
959 | WM8350_IM_EXT_WALL_FB_EINT); | ||
960 | case WM8350_IRQ_EXT_BAT_FB: | ||
961 | return wm8350_clear_bits(wm8350, | ||
962 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
963 | WM8350_IM_EXT_BAT_FB_EINT); | ||
964 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
965 | return wm8350_clear_bits(wm8350, | ||
966 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
967 | WM8350_IM_CODEC_JCK_DET_L_EINT); | ||
968 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
969 | return wm8350_clear_bits(wm8350, | ||
970 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
971 | WM8350_IM_CODEC_JCK_DET_R_EINT); | ||
972 | case WM8350_IRQ_CODEC_MICSCD: | ||
973 | return wm8350_clear_bits(wm8350, | ||
974 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
975 | WM8350_IM_CODEC_MICSCD_EINT); | ||
976 | case WM8350_IRQ_CODEC_MICD: | ||
977 | return wm8350_clear_bits(wm8350, | ||
978 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
979 | WM8350_IM_CODEC_MICD_EINT); | ||
980 | case WM8350_IRQ_WKUP_OFF_STATE: | ||
981 | return wm8350_clear_bits(wm8350, | ||
982 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
983 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
984 | case WM8350_IRQ_WKUP_HIB_STATE: | ||
985 | return wm8350_clear_bits(wm8350, | ||
986 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
987 | WM8350_IM_WKUP_HIB_STATE_EINT); | ||
988 | case WM8350_IRQ_WKUP_CONV_FAULT: | ||
989 | return wm8350_clear_bits(wm8350, | ||
990 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
991 | WM8350_IM_WKUP_CONV_FAULT_EINT); | ||
992 | case WM8350_IRQ_WKUP_WDOG_RST: | ||
993 | return wm8350_clear_bits(wm8350, | ||
994 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
995 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
996 | case WM8350_IRQ_WKUP_GP_PWR_ON: | ||
997 | return wm8350_clear_bits(wm8350, | ||
998 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
999 | WM8350_IM_WKUP_GP_PWR_ON_EINT); | ||
1000 | case WM8350_IRQ_WKUP_ONKEY: | ||
1001 | return wm8350_clear_bits(wm8350, | ||
1002 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
1003 | WM8350_IM_WKUP_ONKEY_EINT); | ||
1004 | case WM8350_IRQ_WKUP_GP_WAKEUP: | ||
1005 | return wm8350_clear_bits(wm8350, | ||
1006 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
1007 | WM8350_IM_WKUP_GP_WAKEUP_EINT); | ||
1008 | case WM8350_IRQ_GPIO(0): | ||
1009 | return wm8350_clear_bits(wm8350, | ||
1010 | WM8350_GPIO_INT_STATUS_MASK, | ||
1011 | WM8350_IM_GP0_EINT); | ||
1012 | case WM8350_IRQ_GPIO(1): | ||
1013 | return wm8350_clear_bits(wm8350, | ||
1014 | WM8350_GPIO_INT_STATUS_MASK, | ||
1015 | WM8350_IM_GP1_EINT); | ||
1016 | case WM8350_IRQ_GPIO(2): | ||
1017 | return wm8350_clear_bits(wm8350, | ||
1018 | WM8350_GPIO_INT_STATUS_MASK, | ||
1019 | WM8350_IM_GP2_EINT); | ||
1020 | case WM8350_IRQ_GPIO(3): | ||
1021 | return wm8350_clear_bits(wm8350, | ||
1022 | WM8350_GPIO_INT_STATUS_MASK, | ||
1023 | WM8350_IM_GP3_EINT); | ||
1024 | case WM8350_IRQ_GPIO(4): | ||
1025 | return wm8350_clear_bits(wm8350, | ||
1026 | WM8350_GPIO_INT_STATUS_MASK, | ||
1027 | WM8350_IM_GP4_EINT); | ||
1028 | case WM8350_IRQ_GPIO(5): | ||
1029 | return wm8350_clear_bits(wm8350, | ||
1030 | WM8350_GPIO_INT_STATUS_MASK, | ||
1031 | WM8350_IM_GP5_EINT); | ||
1032 | case WM8350_IRQ_GPIO(6): | ||
1033 | return wm8350_clear_bits(wm8350, | ||
1034 | WM8350_GPIO_INT_STATUS_MASK, | ||
1035 | WM8350_IM_GP6_EINT); | ||
1036 | case WM8350_IRQ_GPIO(7): | ||
1037 | return wm8350_clear_bits(wm8350, | ||
1038 | WM8350_GPIO_INT_STATUS_MASK, | ||
1039 | WM8350_IM_GP7_EINT); | ||
1040 | case WM8350_IRQ_GPIO(8): | ||
1041 | return wm8350_clear_bits(wm8350, | ||
1042 | WM8350_GPIO_INT_STATUS_MASK, | ||
1043 | WM8350_IM_GP8_EINT); | ||
1044 | case WM8350_IRQ_GPIO(9): | ||
1045 | return wm8350_clear_bits(wm8350, | ||
1046 | WM8350_GPIO_INT_STATUS_MASK, | ||
1047 | WM8350_IM_GP9_EINT); | ||
1048 | case WM8350_IRQ_GPIO(10): | ||
1049 | return wm8350_clear_bits(wm8350, | ||
1050 | WM8350_GPIO_INT_STATUS_MASK, | ||
1051 | WM8350_IM_GP10_EINT); | ||
1052 | case WM8350_IRQ_GPIO(11): | ||
1053 | return wm8350_clear_bits(wm8350, | ||
1054 | WM8350_GPIO_INT_STATUS_MASK, | ||
1055 | WM8350_IM_GP11_EINT); | ||
1056 | case WM8350_IRQ_GPIO(12): | ||
1057 | return wm8350_clear_bits(wm8350, | ||
1058 | WM8350_GPIO_INT_STATUS_MASK, | ||
1059 | WM8350_IM_GP12_EINT); | ||
1060 | default: | ||
1061 | dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n", | ||
1062 | irq); | ||
1063 | return -EINVAL; | ||
1064 | } | ||
1065 | return 0; | ||
1066 | } | ||
1067 | EXPORT_SYMBOL_GPL(wm8350_unmask_irq); | ||
1068 | |||
1069 | /* | ||
1070 | * Cache is always host endian. | ||
1071 | */ | ||
1072 | static int wm8350_create_cache(struct wm8350 *wm8350, int mode) | ||
1073 | { | ||
1074 | int i, ret = 0; | ||
1075 | u16 value; | ||
1076 | const u16 *reg_map; | ||
1077 | |||
1078 | switch (mode) { | ||
1079 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0 | ||
1080 | case 0: | ||
1081 | reg_map = wm8350_mode0_defaults; | ||
1082 | break; | ||
1083 | #endif | ||
1084 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1 | ||
1085 | case 1: | ||
1086 | reg_map = wm8350_mode1_defaults; | ||
1087 | break; | ||
1088 | #endif | ||
1089 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2 | ||
1090 | case 2: | ||
1091 | reg_map = wm8350_mode2_defaults; | ||
1092 | break; | ||
1093 | #endif | ||
1094 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3 | ||
1095 | case 3: | ||
1096 | reg_map = wm8350_mode3_defaults; | ||
1097 | break; | ||
1098 | #endif | ||
1099 | default: | ||
1100 | dev_err(wm8350->dev, "Configuration mode %d not supported\n", | ||
1101 | mode); | ||
1102 | return -EINVAL; | ||
1103 | } | ||
1104 | |||
1105 | wm8350->reg_cache = | ||
1106 | kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL); | ||
1107 | if (wm8350->reg_cache == NULL) | ||
1108 | return -ENOMEM; | ||
1109 | |||
1110 | /* Read the initial cache state back from the device - this is | ||
1111 | * a PMIC so the device many not be in a virgin state and we | ||
1112 | * can't rely on the silicon values. | ||
1113 | */ | ||
1114 | for (i = 0; i < WM8350_MAX_REGISTER; i++) { | ||
1115 | /* audio register range */ | ||
1116 | if (wm8350_reg_io_map[i].readable && | ||
1117 | (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) { | ||
1118 | ret = wm8350->read_dev(wm8350, i, 2, (char *)&value); | ||
1119 | if (ret < 0) { | ||
1120 | dev_err(wm8350->dev, | ||
1121 | "failed to read initial cache value\n"); | ||
1122 | goto out; | ||
1123 | } | ||
1124 | value = be16_to_cpu(value); | ||
1125 | value &= wm8350_reg_io_map[i].readable; | ||
1126 | value &= ~wm8350_reg_io_map[i].vol; | ||
1127 | wm8350->reg_cache[i] = value; | ||
1128 | } else | ||
1129 | wm8350->reg_cache[i] = reg_map[i]; | ||
1130 | } | ||
1131 | |||
1132 | out: | ||
1133 | return ret; | ||
1134 | } | ||
1135 | |||
1136 | /* | ||
1137 | * Register a client device. This is non-fatal since there is no need to | ||
1138 | * fail the entire device init due to a single platform device failing. | ||
1139 | */ | ||
1140 | static void wm8350_client_dev_register(struct wm8350 *wm8350, | ||
1141 | const char *name, | ||
1142 | struct platform_device **pdev) | ||
1143 | { | ||
1144 | int ret; | ||
1145 | |||
1146 | *pdev = platform_device_alloc(name, -1); | ||
1147 | if (pdev == NULL) { | ||
1148 | dev_err(wm8350->dev, "Failed to allocate %s\n", name); | ||
1149 | return; | ||
1150 | } | ||
1151 | |||
1152 | (*pdev)->dev.parent = wm8350->dev; | ||
1153 | platform_set_drvdata(*pdev, wm8350); | ||
1154 | ret = platform_device_add(*pdev); | ||
1155 | if (ret != 0) { | ||
1156 | dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret); | ||
1157 | platform_device_put(*pdev); | ||
1158 | *pdev = NULL; | ||
1159 | } | ||
1160 | } | ||
1161 | |||
1162 | int wm8350_device_init(struct wm8350 *wm8350, int irq, | ||
1163 | struct wm8350_platform_data *pdata) | ||
1164 | { | ||
1165 | int ret = -EINVAL; | ||
1166 | u16 id1, id2, mask, mode; | ||
1167 | |||
1168 | /* get WM8350 revision and config mode */ | ||
1169 | wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1); | ||
1170 | wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2); | ||
1171 | |||
1172 | id1 = be16_to_cpu(id1); | ||
1173 | id2 = be16_to_cpu(id2); | ||
1174 | |||
1175 | if (id1 == 0x6143) { | ||
1176 | switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) { | ||
1177 | case WM8350_REV_E: | ||
1178 | dev_info(wm8350->dev, "Found Rev E device\n"); | ||
1179 | wm8350->rev = WM8350_REV_E; | ||
1180 | break; | ||
1181 | case WM8350_REV_F: | ||
1182 | dev_info(wm8350->dev, "Found Rev F device\n"); | ||
1183 | wm8350->rev = WM8350_REV_F; | ||
1184 | break; | ||
1185 | case WM8350_REV_G: | ||
1186 | dev_info(wm8350->dev, "Found Rev G device\n"); | ||
1187 | wm8350->rev = WM8350_REV_G; | ||
1188 | break; | ||
1189 | default: | ||
1190 | /* For safety we refuse to run on unknown hardware */ | ||
1191 | dev_info(wm8350->dev, "Found unknown rev\n"); | ||
1192 | ret = -ENODEV; | ||
1193 | goto err; | ||
1194 | } | ||
1195 | } else { | ||
1196 | dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n", | ||
1197 | id1); | ||
1198 | ret = -ENODEV; | ||
1199 | goto err; | ||
1200 | } | ||
1201 | |||
1202 | mode = id2 & WM8350_CONF_STS_MASK >> 10; | ||
1203 | mask = id2 & WM8350_CUST_ID_MASK; | ||
1204 | dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask); | ||
1205 | |||
1206 | ret = wm8350_create_cache(wm8350, mode); | ||
1207 | if (ret < 0) { | ||
1208 | printk(KERN_ERR "wm8350: failed to create register cache\n"); | ||
1209 | return ret; | ||
1210 | } | ||
1211 | |||
1212 | if (pdata->init) { | ||
1213 | ret = pdata->init(wm8350); | ||
1214 | if (ret != 0) { | ||
1215 | dev_err(wm8350->dev, "Platform init() failed: %d\n", | ||
1216 | ret); | ||
1217 | goto err; | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | mutex_init(&wm8350->irq_mutex); | ||
1222 | INIT_WORK(&wm8350->irq_work, wm8350_irq_worker); | ||
1223 | if (irq) { | ||
1224 | ret = request_irq(irq, wm8350_irq, 0, | ||
1225 | "wm8350", wm8350); | ||
1226 | if (ret != 0) { | ||
1227 | dev_err(wm8350->dev, "Failed to request IRQ: %d\n", | ||
1228 | ret); | ||
1229 | goto err; | ||
1230 | } | ||
1231 | } else { | ||
1232 | dev_err(wm8350->dev, "No IRQ configured\n"); | ||
1233 | goto err; | ||
1234 | } | ||
1235 | wm8350->chip_irq = irq; | ||
1236 | |||
1237 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0); | ||
1238 | |||
1239 | wm8350_client_dev_register(wm8350, "wm8350-codec", | ||
1240 | &(wm8350->codec.pdev)); | ||
1241 | wm8350_client_dev_register(wm8350, "wm8350-gpio", | ||
1242 | &(wm8350->gpio.pdev)); | ||
1243 | wm8350_client_dev_register(wm8350, "wm8350-power", | ||
1244 | &(wm8350->power.pdev)); | ||
1245 | wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev)); | ||
1246 | wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev)); | ||
1247 | |||
1248 | return 0; | ||
1249 | |||
1250 | err: | ||
1251 | kfree(wm8350->reg_cache); | ||
1252 | return ret; | ||
1253 | } | ||
1254 | EXPORT_SYMBOL_GPL(wm8350_device_init); | ||
1255 | |||
1256 | void wm8350_device_exit(struct wm8350 *wm8350) | ||
1257 | { | ||
1258 | int i; | ||
1259 | |||
1260 | for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++) | ||
1261 | platform_device_unregister(wm8350->pmic.pdev[i]); | ||
1262 | |||
1263 | platform_device_unregister(wm8350->wdt.pdev); | ||
1264 | platform_device_unregister(wm8350->rtc.pdev); | ||
1265 | platform_device_unregister(wm8350->power.pdev); | ||
1266 | platform_device_unregister(wm8350->gpio.pdev); | ||
1267 | platform_device_unregister(wm8350->codec.pdev); | ||
1268 | |||
1269 | free_irq(wm8350->chip_irq, wm8350); | ||
1270 | flush_work(&wm8350->irq_work); | ||
1271 | kfree(wm8350->reg_cache); | ||
1272 | } | ||
1273 | EXPORT_SYMBOL_GPL(wm8350_device_exit); | ||
1274 | |||
1275 | MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver"); | ||
1276 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c new file mode 100644 index 000000000000..ebf99bef392f --- /dev/null +++ b/drivers/mfd/wm8350-gpio.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * wm8350-core.c -- Device access for Wolfson WM8350 | ||
3 | * | ||
4 | * Copyright 2007, 2008 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Liam Girdwood | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/errno.h> | ||
18 | |||
19 | #include <linux/mfd/wm8350/core.h> | ||
20 | #include <linux/mfd/wm8350/gpio.h> | ||
21 | #include <linux/mfd/wm8350/pmic.h> | ||
22 | |||
23 | static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir) | ||
24 | { | ||
25 | int ret; | ||
26 | |||
27 | wm8350_reg_unlock(wm8350); | ||
28 | if (dir == WM8350_GPIO_DIR_OUT) | ||
29 | ret = wm8350_clear_bits(wm8350, | ||
30 | WM8350_GPIO_CONFIGURATION_I_O, | ||
31 | 1 << gpio); | ||
32 | else | ||
33 | ret = wm8350_set_bits(wm8350, | ||
34 | WM8350_GPIO_CONFIGURATION_I_O, | ||
35 | 1 << gpio); | ||
36 | wm8350_reg_lock(wm8350); | ||
37 | return ret; | ||
38 | } | ||
39 | |||
40 | static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db) | ||
41 | { | ||
42 | if (db == WM8350_GPIO_DEBOUNCE_ON) | ||
43 | return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE, | ||
44 | 1 << gpio); | ||
45 | else | ||
46 | return wm8350_clear_bits(wm8350, | ||
47 | WM8350_GPIO_DEBOUNCE, 1 << gpio); | ||
48 | } | ||
49 | |||
50 | static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func) | ||
51 | { | ||
52 | u16 reg; | ||
53 | |||
54 | wm8350_reg_unlock(wm8350); | ||
55 | switch (gpio) { | ||
56 | case 0: | ||
57 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1) | ||
58 | & ~WM8350_GP0_FN_MASK; | ||
59 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1, | ||
60 | reg | ((func & 0xf) << 0)); | ||
61 | break; | ||
62 | case 1: | ||
63 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1) | ||
64 | & ~WM8350_GP1_FN_MASK; | ||
65 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1, | ||
66 | reg | ((func & 0xf) << 4)); | ||
67 | break; | ||
68 | case 2: | ||
69 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1) | ||
70 | & ~WM8350_GP2_FN_MASK; | ||
71 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1, | ||
72 | reg | ((func & 0xf) << 8)); | ||
73 | break; | ||
74 | case 3: | ||
75 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1) | ||
76 | & ~WM8350_GP3_FN_MASK; | ||
77 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1, | ||
78 | reg | ((func & 0xf) << 12)); | ||
79 | break; | ||
80 | case 4: | ||
81 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2) | ||
82 | & ~WM8350_GP4_FN_MASK; | ||
83 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2, | ||
84 | reg | ((func & 0xf) << 0)); | ||
85 | break; | ||
86 | case 5: | ||
87 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2) | ||
88 | & ~WM8350_GP5_FN_MASK; | ||
89 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2, | ||
90 | reg | ((func & 0xf) << 4)); | ||
91 | break; | ||
92 | case 6: | ||
93 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2) | ||
94 | & ~WM8350_GP6_FN_MASK; | ||
95 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2, | ||
96 | reg | ((func & 0xf) << 8)); | ||
97 | break; | ||
98 | case 7: | ||
99 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2) | ||
100 | & ~WM8350_GP7_FN_MASK; | ||
101 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2, | ||
102 | reg | ((func & 0xf) << 12)); | ||
103 | break; | ||
104 | case 8: | ||
105 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3) | ||
106 | & ~WM8350_GP8_FN_MASK; | ||
107 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3, | ||
108 | reg | ((func & 0xf) << 0)); | ||
109 | break; | ||
110 | case 9: | ||
111 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3) | ||
112 | & ~WM8350_GP9_FN_MASK; | ||
113 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3, | ||
114 | reg | ((func & 0xf) << 4)); | ||
115 | break; | ||
116 | case 10: | ||
117 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3) | ||
118 | & ~WM8350_GP10_FN_MASK; | ||
119 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3, | ||
120 | reg | ((func & 0xf) << 8)); | ||
121 | break; | ||
122 | case 11: | ||
123 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3) | ||
124 | & ~WM8350_GP11_FN_MASK; | ||
125 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3, | ||
126 | reg | ((func & 0xf) << 12)); | ||
127 | break; | ||
128 | case 12: | ||
129 | reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4) | ||
130 | & ~WM8350_GP12_FN_MASK; | ||
131 | wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4, | ||
132 | reg | ((func & 0xf) << 0)); | ||
133 | break; | ||
134 | default: | ||
135 | wm8350_reg_lock(wm8350); | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | |||
139 | wm8350_reg_lock(wm8350); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up) | ||
144 | { | ||
145 | if (up) | ||
146 | return wm8350_set_bits(wm8350, | ||
147 | WM8350_GPIO_PIN_PULL_UP_CONTROL, | ||
148 | 1 << gpio); | ||
149 | else | ||
150 | return wm8350_clear_bits(wm8350, | ||
151 | WM8350_GPIO_PIN_PULL_UP_CONTROL, | ||
152 | 1 << gpio); | ||
153 | } | ||
154 | |||
155 | static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down) | ||
156 | { | ||
157 | if (down) | ||
158 | return wm8350_set_bits(wm8350, | ||
159 | WM8350_GPIO_PULL_DOWN_CONTROL, | ||
160 | 1 << gpio); | ||
161 | else | ||
162 | return wm8350_clear_bits(wm8350, | ||
163 | WM8350_GPIO_PULL_DOWN_CONTROL, | ||
164 | 1 << gpio); | ||
165 | } | ||
166 | |||
167 | static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol) | ||
168 | { | ||
169 | if (pol == WM8350_GPIO_ACTIVE_HIGH) | ||
170 | return wm8350_set_bits(wm8350, | ||
171 | WM8350_GPIO_PIN_POLARITY_TYPE, | ||
172 | 1 << gpio); | ||
173 | else | ||
174 | return wm8350_clear_bits(wm8350, | ||
175 | WM8350_GPIO_PIN_POLARITY_TYPE, | ||
176 | 1 << gpio); | ||
177 | } | ||
178 | |||
179 | static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert) | ||
180 | { | ||
181 | if (invert == WM8350_GPIO_INVERT_ON) | ||
182 | return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio); | ||
183 | else | ||
184 | return wm8350_clear_bits(wm8350, | ||
185 | WM8350_GPIO_INT_MODE, 1 << gpio); | ||
186 | } | ||
187 | |||
188 | int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func, | ||
189 | int pol, int pull, int invert, int debounce) | ||
190 | { | ||
191 | /* make sure we never pull up and down at the same time */ | ||
192 | if (pull == WM8350_GPIO_PULL_NONE) { | ||
193 | if (gpio_set_pull_up(wm8350, gpio, 0)) | ||
194 | goto err; | ||
195 | if (gpio_set_pull_down(wm8350, gpio, 0)) | ||
196 | goto err; | ||
197 | } else if (pull == WM8350_GPIO_PULL_UP) { | ||
198 | if (gpio_set_pull_down(wm8350, gpio, 0)) | ||
199 | goto err; | ||
200 | if (gpio_set_pull_up(wm8350, gpio, 1)) | ||
201 | goto err; | ||
202 | } else if (pull == WM8350_GPIO_PULL_DOWN) { | ||
203 | if (gpio_set_pull_up(wm8350, gpio, 0)) | ||
204 | goto err; | ||
205 | if (gpio_set_pull_down(wm8350, gpio, 1)) | ||
206 | goto err; | ||
207 | } | ||
208 | |||
209 | if (gpio_set_invert(wm8350, gpio, invert)) | ||
210 | goto err; | ||
211 | if (gpio_set_polarity(wm8350, gpio, pol)) | ||
212 | goto err; | ||
213 | if (gpio_set_debounce(wm8350, gpio, debounce)) | ||
214 | goto err; | ||
215 | if (gpio_set_dir(wm8350, gpio, dir)) | ||
216 | goto err; | ||
217 | return gpio_set_func(wm8350, gpio, func); | ||
218 | |||
219 | err: | ||
220 | return -EIO; | ||
221 | } | ||
222 | EXPORT_SYMBOL_GPL(wm8350_gpio_config); | ||
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c new file mode 100644 index 000000000000..8dfe21bb3bd1 --- /dev/null +++ b/drivers/mfd/wm8350-i2c.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * wm8350-i2c.c -- Generic I2C driver for Wolfson WM8350 PMIC | ||
3 | * | ||
4 | * This driver defines and configures the WM8350 for the Freescale i.MX32ADS. | ||
5 | * | ||
6 | * Copyright 2007, 2008 Wolfson Microelectronics PLC. | ||
7 | * | ||
8 | * Author: Liam Girdwood | ||
9 | * linux@wolfsonmicro.com | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/mfd/wm8350/core.h> | ||
24 | |||
25 | static int wm8350_i2c_read_device(struct wm8350 *wm8350, char reg, | ||
26 | int bytes, void *dest) | ||
27 | { | ||
28 | int ret; | ||
29 | |||
30 | ret = i2c_master_send(wm8350->i2c_client, ®, 1); | ||
31 | if (ret < 0) | ||
32 | return ret; | ||
33 | return i2c_master_recv(wm8350->i2c_client, dest, bytes); | ||
34 | } | ||
35 | |||
36 | static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg, | ||
37 | int bytes, void *src) | ||
38 | { | ||
39 | /* we add 1 byte for device register */ | ||
40 | u8 msg[(WM8350_MAX_REGISTER << 1) + 1]; | ||
41 | |||
42 | if (bytes > ((WM8350_MAX_REGISTER << 1) + 1)) | ||
43 | return -EINVAL; | ||
44 | |||
45 | msg[0] = reg; | ||
46 | memcpy(&msg[1], src, bytes); | ||
47 | return i2c_master_send(wm8350->i2c_client, msg, bytes + 1); | ||
48 | } | ||
49 | |||
50 | static int wm8350_i2c_probe(struct i2c_client *i2c, | ||
51 | const struct i2c_device_id *id) | ||
52 | { | ||
53 | struct wm8350 *wm8350; | ||
54 | int ret = 0; | ||
55 | |||
56 | wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL); | ||
57 | if (wm8350 == NULL) { | ||
58 | kfree(i2c); | ||
59 | return -ENOMEM; | ||
60 | } | ||
61 | |||
62 | i2c_set_clientdata(i2c, wm8350); | ||
63 | wm8350->dev = &i2c->dev; | ||
64 | wm8350->i2c_client = i2c; | ||
65 | wm8350->read_dev = wm8350_i2c_read_device; | ||
66 | wm8350->write_dev = wm8350_i2c_write_device; | ||
67 | |||
68 | ret = wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data); | ||
69 | if (ret < 0) | ||
70 | goto err; | ||
71 | |||
72 | return ret; | ||
73 | |||
74 | err: | ||
75 | kfree(wm8350); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | static int wm8350_i2c_remove(struct i2c_client *i2c) | ||
80 | { | ||
81 | struct wm8350 *wm8350 = i2c_get_clientdata(i2c); | ||
82 | |||
83 | wm8350_device_exit(wm8350); | ||
84 | kfree(wm8350); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static const struct i2c_device_id wm8350_i2c_id[] = { | ||
90 | { "wm8350", 0 }, | ||
91 | { } | ||
92 | }; | ||
93 | MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id); | ||
94 | |||
95 | |||
96 | static struct i2c_driver wm8350_i2c_driver = { | ||
97 | .driver = { | ||
98 | .name = "wm8350", | ||
99 | .owner = THIS_MODULE, | ||
100 | }, | ||
101 | .probe = wm8350_i2c_probe, | ||
102 | .remove = wm8350_i2c_remove, | ||
103 | .id_table = wm8350_i2c_id, | ||
104 | }; | ||
105 | |||
106 | static int __init wm8350_i2c_init(void) | ||
107 | { | ||
108 | return i2c_add_driver(&wm8350_i2c_driver); | ||
109 | } | ||
110 | /* init early so consumer devices can complete system boot */ | ||
111 | subsys_initcall(wm8350_i2c_init); | ||
112 | |||
113 | static void __exit wm8350_i2c_exit(void) | ||
114 | { | ||
115 | i2c_del_driver(&wm8350_i2c_driver); | ||
116 | } | ||
117 | module_exit(wm8350_i2c_exit); | ||
118 | |||
119 | MODULE_DESCRIPTION("I2C support for the WM8350 AudioPlus PMIC"); | ||
120 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c new file mode 100644 index 000000000000..974678db22cd --- /dev/null +++ b/drivers/mfd/wm8350-regmap.c | |||
@@ -0,0 +1,1347 @@ | |||
1 | /* | ||
2 | * wm8350-regmap.c -- Wolfson Microelectronics WM8350 register map | ||
3 | * | ||
4 | * This file splits out the tables describing the defaults and access | ||
5 | * status of the WM8350 registers since they are rather large. | ||
6 | * | ||
7 | * Copyright 2007, 2008 Wolfson Microelectronics PLC. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/mfd/wm8350/core.h> | ||
16 | |||
17 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0 | ||
18 | |||
19 | #undef WM8350_HAVE_CONFIG_MODE | ||
20 | #define WM8350_HAVE_CONFIG_MODE | ||
21 | |||
22 | const u16 wm8350_mode0_defaults[] = { | ||
23 | 0x17FF, /* R0 - Reset/ID */ | ||
24 | 0x1000, /* R1 - ID */ | ||
25 | 0x0000, /* R2 */ | ||
26 | 0x1002, /* R3 - System Control 1 */ | ||
27 | 0x0004, /* R4 - System Control 2 */ | ||
28 | 0x0000, /* R5 - System Hibernate */ | ||
29 | 0x8A00, /* R6 - Interface Control */ | ||
30 | 0x0000, /* R7 */ | ||
31 | 0x8000, /* R8 - Power mgmt (1) */ | ||
32 | 0x0000, /* R9 - Power mgmt (2) */ | ||
33 | 0x0000, /* R10 - Power mgmt (3) */ | ||
34 | 0x2000, /* R11 - Power mgmt (4) */ | ||
35 | 0x0E00, /* R12 - Power mgmt (5) */ | ||
36 | 0x0000, /* R13 - Power mgmt (6) */ | ||
37 | 0x0000, /* R14 - Power mgmt (7) */ | ||
38 | 0x0000, /* R15 */ | ||
39 | 0x0000, /* R16 - RTC Seconds/Minutes */ | ||
40 | 0x0100, /* R17 - RTC Hours/Day */ | ||
41 | 0x0101, /* R18 - RTC Date/Month */ | ||
42 | 0x1400, /* R19 - RTC Year */ | ||
43 | 0x0000, /* R20 - Alarm Seconds/Minutes */ | ||
44 | 0x0000, /* R21 - Alarm Hours/Day */ | ||
45 | 0x0000, /* R22 - Alarm Date/Month */ | ||
46 | 0x0320, /* R23 - RTC Time Control */ | ||
47 | 0x0000, /* R24 - System Interrupts */ | ||
48 | 0x0000, /* R25 - Interrupt Status 1 */ | ||
49 | 0x0000, /* R26 - Interrupt Status 2 */ | ||
50 | 0x0000, /* R27 - Power Up Interrupt Status */ | ||
51 | 0x0000, /* R28 - Under Voltage Interrupt status */ | ||
52 | 0x0000, /* R29 - Over Current Interrupt status */ | ||
53 | 0x0000, /* R30 - GPIO Interrupt Status */ | ||
54 | 0x0000, /* R31 - Comparator Interrupt Status */ | ||
55 | 0x3FFF, /* R32 - System Interrupts Mask */ | ||
56 | 0x0000, /* R33 - Interrupt Status 1 Mask */ | ||
57 | 0x0000, /* R34 - Interrupt Status 2 Mask */ | ||
58 | 0x0000, /* R35 - Power Up Interrupt Status Mask */ | ||
59 | 0x0000, /* R36 - Under Voltage Interrupt status Mask */ | ||
60 | 0x0000, /* R37 - Over Current Interrupt status Mask */ | ||
61 | 0x0000, /* R38 - GPIO Interrupt Status Mask */ | ||
62 | 0x0000, /* R39 - Comparator Interrupt Status Mask */ | ||
63 | 0x0040, /* R40 - Clock Control 1 */ | ||
64 | 0x0000, /* R41 - Clock Control 2 */ | ||
65 | 0x3B00, /* R42 - FLL Control 1 */ | ||
66 | 0x7086, /* R43 - FLL Control 2 */ | ||
67 | 0xC226, /* R44 - FLL Control 3 */ | ||
68 | 0x0000, /* R45 - FLL Control 4 */ | ||
69 | 0x0000, /* R46 */ | ||
70 | 0x0000, /* R47 */ | ||
71 | 0x0000, /* R48 - DAC Control */ | ||
72 | 0x0000, /* R49 */ | ||
73 | 0x00C0, /* R50 - DAC Digital Volume L */ | ||
74 | 0x00C0, /* R51 - DAC Digital Volume R */ | ||
75 | 0x0000, /* R52 */ | ||
76 | 0x0040, /* R53 - DAC LR Rate */ | ||
77 | 0x0000, /* R54 - DAC Clock Control */ | ||
78 | 0x0000, /* R55 */ | ||
79 | 0x0000, /* R56 */ | ||
80 | 0x0000, /* R57 */ | ||
81 | 0x4000, /* R58 - DAC Mute */ | ||
82 | 0x0000, /* R59 - DAC Mute Volume */ | ||
83 | 0x0000, /* R60 - DAC Side */ | ||
84 | 0x0000, /* R61 */ | ||
85 | 0x0000, /* R62 */ | ||
86 | 0x0000, /* R63 */ | ||
87 | 0x8000, /* R64 - ADC Control */ | ||
88 | 0x0000, /* R65 */ | ||
89 | 0x00C0, /* R66 - ADC Digital Volume L */ | ||
90 | 0x00C0, /* R67 - ADC Digital Volume R */ | ||
91 | 0x0000, /* R68 - ADC Divider */ | ||
92 | 0x0000, /* R69 */ | ||
93 | 0x0040, /* R70 - ADC LR Rate */ | ||
94 | 0x0000, /* R71 */ | ||
95 | 0x0303, /* R72 - Input Control */ | ||
96 | 0x0000, /* R73 - IN3 Input Control */ | ||
97 | 0x0000, /* R74 - Mic Bias Control */ | ||
98 | 0x0000, /* R75 */ | ||
99 | 0x0000, /* R76 - Output Control */ | ||
100 | 0x0000, /* R77 - Jack Detect */ | ||
101 | 0x0000, /* R78 - Anti Pop Control */ | ||
102 | 0x0000, /* R79 */ | ||
103 | 0x0040, /* R80 - Left Input Volume */ | ||
104 | 0x0040, /* R81 - Right Input Volume */ | ||
105 | 0x0000, /* R82 */ | ||
106 | 0x0000, /* R83 */ | ||
107 | 0x0000, /* R84 */ | ||
108 | 0x0000, /* R85 */ | ||
109 | 0x0000, /* R86 */ | ||
110 | 0x0000, /* R87 */ | ||
111 | 0x0800, /* R88 - Left Mixer Control */ | ||
112 | 0x1000, /* R89 - Right Mixer Control */ | ||
113 | 0x0000, /* R90 */ | ||
114 | 0x0000, /* R91 */ | ||
115 | 0x0000, /* R92 - OUT3 Mixer Control */ | ||
116 | 0x0000, /* R93 - OUT4 Mixer Control */ | ||
117 | 0x0000, /* R94 */ | ||
118 | 0x0000, /* R95 */ | ||
119 | 0x0000, /* R96 - Output Left Mixer Volume */ | ||
120 | 0x0000, /* R97 - Output Right Mixer Volume */ | ||
121 | 0x0000, /* R98 - Input Mixer Volume L */ | ||
122 | 0x0000, /* R99 - Input Mixer Volume R */ | ||
123 | 0x0000, /* R100 - Input Mixer Volume */ | ||
124 | 0x0000, /* R101 */ | ||
125 | 0x0000, /* R102 */ | ||
126 | 0x0000, /* R103 */ | ||
127 | 0x00E4, /* R104 - LOUT1 Volume */ | ||
128 | 0x00E4, /* R105 - ROUT1 Volume */ | ||
129 | 0x00E4, /* R106 - LOUT2 Volume */ | ||
130 | 0x02E4, /* R107 - ROUT2 Volume */ | ||
131 | 0x0000, /* R108 */ | ||
132 | 0x0000, /* R109 */ | ||
133 | 0x0000, /* R110 */ | ||
134 | 0x0000, /* R111 - BEEP Volume */ | ||
135 | 0x0A00, /* R112 - AI Formating */ | ||
136 | 0x0000, /* R113 - ADC DAC COMP */ | ||
137 | 0x0020, /* R114 - AI ADC Control */ | ||
138 | 0x0020, /* R115 - AI DAC Control */ | ||
139 | 0x0000, /* R116 - AIF Test */ | ||
140 | 0x0000, /* R117 */ | ||
141 | 0x0000, /* R118 */ | ||
142 | 0x0000, /* R119 */ | ||
143 | 0x0000, /* R120 */ | ||
144 | 0x0000, /* R121 */ | ||
145 | 0x0000, /* R122 */ | ||
146 | 0x0000, /* R123 */ | ||
147 | 0x0000, /* R124 */ | ||
148 | 0x0000, /* R125 */ | ||
149 | 0x0000, /* R126 */ | ||
150 | 0x0000, /* R127 */ | ||
151 | 0x1FFF, /* R128 - GPIO Debounce */ | ||
152 | 0x0000, /* R129 - GPIO Pin pull up Control */ | ||
153 | 0x03FC, /* R130 - GPIO Pull down Control */ | ||
154 | 0x0000, /* R131 - GPIO Interrupt Mode */ | ||
155 | 0x0000, /* R132 */ | ||
156 | 0x0000, /* R133 - GPIO Control */ | ||
157 | 0x0FFC, /* R134 - GPIO Configuration (i/o) */ | ||
158 | 0x0FFC, /* R135 - GPIO Pin Polarity / Type */ | ||
159 | 0x0000, /* R136 */ | ||
160 | 0x0000, /* R137 */ | ||
161 | 0x0000, /* R138 */ | ||
162 | 0x0000, /* R139 */ | ||
163 | 0x0013, /* R140 - GPIO Function Select 1 */ | ||
164 | 0x0000, /* R141 - GPIO Function Select 2 */ | ||
165 | 0x0000, /* R142 - GPIO Function Select 3 */ | ||
166 | 0x0003, /* R143 - GPIO Function Select 4 */ | ||
167 | 0x0000, /* R144 - Digitiser Control (1) */ | ||
168 | 0x0002, /* R145 - Digitiser Control (2) */ | ||
169 | 0x0000, /* R146 */ | ||
170 | 0x0000, /* R147 */ | ||
171 | 0x0000, /* R148 */ | ||
172 | 0x0000, /* R149 */ | ||
173 | 0x0000, /* R150 */ | ||
174 | 0x0000, /* R151 */ | ||
175 | 0x7000, /* R152 - AUX1 Readback */ | ||
176 | 0x7000, /* R153 - AUX2 Readback */ | ||
177 | 0x7000, /* R154 - AUX3 Readback */ | ||
178 | 0x7000, /* R155 - AUX4 Readback */ | ||
179 | 0x0000, /* R156 - USB Voltage Readback */ | ||
180 | 0x0000, /* R157 - LINE Voltage Readback */ | ||
181 | 0x0000, /* R158 - BATT Voltage Readback */ | ||
182 | 0x0000, /* R159 - Chip Temp Readback */ | ||
183 | 0x0000, /* R160 */ | ||
184 | 0x0000, /* R161 */ | ||
185 | 0x0000, /* R162 */ | ||
186 | 0x0000, /* R163 - Generic Comparator Control */ | ||
187 | 0x0000, /* R164 - Generic comparator 1 */ | ||
188 | 0x0000, /* R165 - Generic comparator 2 */ | ||
189 | 0x0000, /* R166 - Generic comparator 3 */ | ||
190 | 0x0000, /* R167 - Generic comparator 4 */ | ||
191 | 0xA00F, /* R168 - Battery Charger Control 1 */ | ||
192 | 0x0B06, /* R169 - Battery Charger Control 2 */ | ||
193 | 0x0000, /* R170 - Battery Charger Control 3 */ | ||
194 | 0x0000, /* R171 */ | ||
195 | 0x0000, /* R172 - Current Sink Driver A */ | ||
196 | 0x0000, /* R173 - CSA Flash control */ | ||
197 | 0x0000, /* R174 - Current Sink Driver B */ | ||
198 | 0x0000, /* R175 - CSB Flash control */ | ||
199 | 0x0000, /* R176 - DCDC/LDO requested */ | ||
200 | 0x002D, /* R177 - DCDC Active options */ | ||
201 | 0x0000, /* R178 - DCDC Sleep options */ | ||
202 | 0x0025, /* R179 - Power-check comparator */ | ||
203 | 0x000E, /* R180 - DCDC1 Control */ | ||
204 | 0x0000, /* R181 - DCDC1 Timeouts */ | ||
205 | 0x1006, /* R182 - DCDC1 Low Power */ | ||
206 | 0x0018, /* R183 - DCDC2 Control */ | ||
207 | 0x0000, /* R184 - DCDC2 Timeouts */ | ||
208 | 0x0000, /* R185 */ | ||
209 | 0x0000, /* R186 - DCDC3 Control */ | ||
210 | 0x0000, /* R187 - DCDC3 Timeouts */ | ||
211 | 0x0006, /* R188 - DCDC3 Low Power */ | ||
212 | 0x0000, /* R189 - DCDC4 Control */ | ||
213 | 0x0000, /* R190 - DCDC4 Timeouts */ | ||
214 | 0x0006, /* R191 - DCDC4 Low Power */ | ||
215 | 0x0008, /* R192 - DCDC5 Control */ | ||
216 | 0x0000, /* R193 - DCDC5 Timeouts */ | ||
217 | 0x0000, /* R194 */ | ||
218 | 0x0000, /* R195 - DCDC6 Control */ | ||
219 | 0x0000, /* R196 - DCDC6 Timeouts */ | ||
220 | 0x0006, /* R197 - DCDC6 Low Power */ | ||
221 | 0x0000, /* R198 */ | ||
222 | 0x0003, /* R199 - Limit Switch Control */ | ||
223 | 0x001C, /* R200 - LDO1 Control */ | ||
224 | 0x0000, /* R201 - LDO1 Timeouts */ | ||
225 | 0x001C, /* R202 - LDO1 Low Power */ | ||
226 | 0x001B, /* R203 - LDO2 Control */ | ||
227 | 0x0000, /* R204 - LDO2 Timeouts */ | ||
228 | 0x001C, /* R205 - LDO2 Low Power */ | ||
229 | 0x001B, /* R206 - LDO3 Control */ | ||
230 | 0x0000, /* R207 - LDO3 Timeouts */ | ||
231 | 0x001C, /* R208 - LDO3 Low Power */ | ||
232 | 0x001B, /* R209 - LDO4 Control */ | ||
233 | 0x0000, /* R210 - LDO4 Timeouts */ | ||
234 | 0x001C, /* R211 - LDO4 Low Power */ | ||
235 | 0x0000, /* R212 */ | ||
236 | 0x0000, /* R213 */ | ||
237 | 0x0000, /* R214 */ | ||
238 | 0x0000, /* R215 - VCC_FAULT Masks */ | ||
239 | 0x001F, /* R216 - Main Bandgap Control */ | ||
240 | 0x0000, /* R217 - OSC Control */ | ||
241 | 0x9000, /* R218 - RTC Tick Control */ | ||
242 | 0x0000, /* R219 */ | ||
243 | 0x4000, /* R220 - RAM BIST 1 */ | ||
244 | 0x0000, /* R221 */ | ||
245 | 0x0000, /* R222 */ | ||
246 | 0x0000, /* R223 */ | ||
247 | 0x0000, /* R224 */ | ||
248 | 0x0000, /* R225 - DCDC/LDO status */ | ||
249 | 0x0000, /* R226 */ | ||
250 | 0x0000, /* R227 */ | ||
251 | 0x0000, /* R228 */ | ||
252 | 0x0000, /* R229 */ | ||
253 | 0xE000, /* R230 - GPIO Pin Status */ | ||
254 | 0x0000, /* R231 */ | ||
255 | 0x0000, /* R232 */ | ||
256 | 0x0000, /* R233 */ | ||
257 | 0x0000, /* R234 */ | ||
258 | 0x0000, /* R235 */ | ||
259 | 0x0000, /* R236 */ | ||
260 | 0x0000, /* R237 */ | ||
261 | 0x0000, /* R238 */ | ||
262 | 0x0000, /* R239 */ | ||
263 | 0x0000, /* R240 */ | ||
264 | 0x0000, /* R241 */ | ||
265 | 0x0000, /* R242 */ | ||
266 | 0x0000, /* R243 */ | ||
267 | 0x0000, /* R244 */ | ||
268 | 0x0000, /* R245 */ | ||
269 | 0x0000, /* R246 */ | ||
270 | 0x0000, /* R247 */ | ||
271 | 0x0000, /* R248 */ | ||
272 | 0x0000, /* R249 */ | ||
273 | 0x0000, /* R250 */ | ||
274 | 0x0000, /* R251 */ | ||
275 | 0x0000, /* R252 */ | ||
276 | 0x0000, /* R253 */ | ||
277 | 0x0000, /* R254 */ | ||
278 | 0x0000, /* R255 */ | ||
279 | }; | ||
280 | #endif | ||
281 | |||
282 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1 | ||
283 | |||
284 | #undef WM8350_HAVE_CONFIG_MODE | ||
285 | #define WM8350_HAVE_CONFIG_MODE | ||
286 | |||
287 | const u16 wm8350_mode1_defaults[] = { | ||
288 | 0x17FF, /* R0 - Reset/ID */ | ||
289 | 0x1000, /* R1 - ID */ | ||
290 | 0x0000, /* R2 */ | ||
291 | 0x1002, /* R3 - System Control 1 */ | ||
292 | 0x0014, /* R4 - System Control 2 */ | ||
293 | 0x0000, /* R5 - System Hibernate */ | ||
294 | 0x8A00, /* R6 - Interface Control */ | ||
295 | 0x0000, /* R7 */ | ||
296 | 0x8000, /* R8 - Power mgmt (1) */ | ||
297 | 0x0000, /* R9 - Power mgmt (2) */ | ||
298 | 0x0000, /* R10 - Power mgmt (3) */ | ||
299 | 0x2000, /* R11 - Power mgmt (4) */ | ||
300 | 0x0E00, /* R12 - Power mgmt (5) */ | ||
301 | 0x0000, /* R13 - Power mgmt (6) */ | ||
302 | 0x0000, /* R14 - Power mgmt (7) */ | ||
303 | 0x0000, /* R15 */ | ||
304 | 0x0000, /* R16 - RTC Seconds/Minutes */ | ||
305 | 0x0100, /* R17 - RTC Hours/Day */ | ||
306 | 0x0101, /* R18 - RTC Date/Month */ | ||
307 | 0x1400, /* R19 - RTC Year */ | ||
308 | 0x0000, /* R20 - Alarm Seconds/Minutes */ | ||
309 | 0x0000, /* R21 - Alarm Hours/Day */ | ||
310 | 0x0000, /* R22 - Alarm Date/Month */ | ||
311 | 0x0320, /* R23 - RTC Time Control */ | ||
312 | 0x0000, /* R24 - System Interrupts */ | ||
313 | 0x0000, /* R25 - Interrupt Status 1 */ | ||
314 | 0x0000, /* R26 - Interrupt Status 2 */ | ||
315 | 0x0000, /* R27 - Power Up Interrupt Status */ | ||
316 | 0x0000, /* R28 - Under Voltage Interrupt status */ | ||
317 | 0x0000, /* R29 - Over Current Interrupt status */ | ||
318 | 0x0000, /* R30 - GPIO Interrupt Status */ | ||
319 | 0x0000, /* R31 - Comparator Interrupt Status */ | ||
320 | 0x3FFF, /* R32 - System Interrupts Mask */ | ||
321 | 0x0000, /* R33 - Interrupt Status 1 Mask */ | ||
322 | 0x0000, /* R34 - Interrupt Status 2 Mask */ | ||
323 | 0x0000, /* R35 - Power Up Interrupt Status Mask */ | ||
324 | 0x0000, /* R36 - Under Voltage Interrupt status Mask */ | ||
325 | 0x0000, /* R37 - Over Current Interrupt status Mask */ | ||
326 | 0x0000, /* R38 - GPIO Interrupt Status Mask */ | ||
327 | 0x0000, /* R39 - Comparator Interrupt Status Mask */ | ||
328 | 0x0040, /* R40 - Clock Control 1 */ | ||
329 | 0x0000, /* R41 - Clock Control 2 */ | ||
330 | 0x3B00, /* R42 - FLL Control 1 */ | ||
331 | 0x7086, /* R43 - FLL Control 2 */ | ||
332 | 0xC226, /* R44 - FLL Control 3 */ | ||
333 | 0x0000, /* R45 - FLL Control 4 */ | ||
334 | 0x0000, /* R46 */ | ||
335 | 0x0000, /* R47 */ | ||
336 | 0x0000, /* R48 - DAC Control */ | ||
337 | 0x0000, /* R49 */ | ||
338 | 0x00C0, /* R50 - DAC Digital Volume L */ | ||
339 | 0x00C0, /* R51 - DAC Digital Volume R */ | ||
340 | 0x0000, /* R52 */ | ||
341 | 0x0040, /* R53 - DAC LR Rate */ | ||
342 | 0x0000, /* R54 - DAC Clock Control */ | ||
343 | 0x0000, /* R55 */ | ||
344 | 0x0000, /* R56 */ | ||
345 | 0x0000, /* R57 */ | ||
346 | 0x4000, /* R58 - DAC Mute */ | ||
347 | 0x0000, /* R59 - DAC Mute Volume */ | ||
348 | 0x0000, /* R60 - DAC Side */ | ||
349 | 0x0000, /* R61 */ | ||
350 | 0x0000, /* R62 */ | ||
351 | 0x0000, /* R63 */ | ||
352 | 0x8000, /* R64 - ADC Control */ | ||
353 | 0x0000, /* R65 */ | ||
354 | 0x00C0, /* R66 - ADC Digital Volume L */ | ||
355 | 0x00C0, /* R67 - ADC Digital Volume R */ | ||
356 | 0x0000, /* R68 - ADC Divider */ | ||
357 | 0x0000, /* R69 */ | ||
358 | 0x0040, /* R70 - ADC LR Rate */ | ||
359 | 0x0000, /* R71 */ | ||
360 | 0x0303, /* R72 - Input Control */ | ||
361 | 0x0000, /* R73 - IN3 Input Control */ | ||
362 | 0x0000, /* R74 - Mic Bias Control */ | ||
363 | 0x0000, /* R75 */ | ||
364 | 0x0000, /* R76 - Output Control */ | ||
365 | 0x0000, /* R77 - Jack Detect */ | ||
366 | 0x0000, /* R78 - Anti Pop Control */ | ||
367 | 0x0000, /* R79 */ | ||
368 | 0x0040, /* R80 - Left Input Volume */ | ||
369 | 0x0040, /* R81 - Right Input Volume */ | ||
370 | 0x0000, /* R82 */ | ||
371 | 0x0000, /* R83 */ | ||
372 | 0x0000, /* R84 */ | ||
373 | 0x0000, /* R85 */ | ||
374 | 0x0000, /* R86 */ | ||
375 | 0x0000, /* R87 */ | ||
376 | 0x0800, /* R88 - Left Mixer Control */ | ||
377 | 0x1000, /* R89 - Right Mixer Control */ | ||
378 | 0x0000, /* R90 */ | ||
379 | 0x0000, /* R91 */ | ||
380 | 0x0000, /* R92 - OUT3 Mixer Control */ | ||
381 | 0x0000, /* R93 - OUT4 Mixer Control */ | ||
382 | 0x0000, /* R94 */ | ||
383 | 0x0000, /* R95 */ | ||
384 | 0x0000, /* R96 - Output Left Mixer Volume */ | ||
385 | 0x0000, /* R97 - Output Right Mixer Volume */ | ||
386 | 0x0000, /* R98 - Input Mixer Volume L */ | ||
387 | 0x0000, /* R99 - Input Mixer Volume R */ | ||
388 | 0x0000, /* R100 - Input Mixer Volume */ | ||
389 | 0x0000, /* R101 */ | ||
390 | 0x0000, /* R102 */ | ||
391 | 0x0000, /* R103 */ | ||
392 | 0x00E4, /* R104 - LOUT1 Volume */ | ||
393 | 0x00E4, /* R105 - ROUT1 Volume */ | ||
394 | 0x00E4, /* R106 - LOUT2 Volume */ | ||
395 | 0x02E4, /* R107 - ROUT2 Volume */ | ||
396 | 0x0000, /* R108 */ | ||
397 | 0x0000, /* R109 */ | ||
398 | 0x0000, /* R110 */ | ||
399 | 0x0000, /* R111 - BEEP Volume */ | ||
400 | 0x0A00, /* R112 - AI Formating */ | ||
401 | 0x0000, /* R113 - ADC DAC COMP */ | ||
402 | 0x0020, /* R114 - AI ADC Control */ | ||
403 | 0x0020, /* R115 - AI DAC Control */ | ||
404 | 0x0000, /* R116 - AIF Test */ | ||
405 | 0x0000, /* R117 */ | ||
406 | 0x0000, /* R118 */ | ||
407 | 0x0000, /* R119 */ | ||
408 | 0x0000, /* R120 */ | ||
409 | 0x0000, /* R121 */ | ||
410 | 0x0000, /* R122 */ | ||
411 | 0x0000, /* R123 */ | ||
412 | 0x0000, /* R124 */ | ||
413 | 0x0000, /* R125 */ | ||
414 | 0x0000, /* R126 */ | ||
415 | 0x0000, /* R127 */ | ||
416 | 0x1FFF, /* R128 - GPIO Debounce */ | ||
417 | 0x0000, /* R129 - GPIO Pin pull up Control */ | ||
418 | 0x03FC, /* R130 - GPIO Pull down Control */ | ||
419 | 0x0000, /* R131 - GPIO Interrupt Mode */ | ||
420 | 0x0000, /* R132 */ | ||
421 | 0x0000, /* R133 - GPIO Control */ | ||
422 | 0x00FB, /* R134 - GPIO Configuration (i/o) */ | ||
423 | 0x04FE, /* R135 - GPIO Pin Polarity / Type */ | ||
424 | 0x0000, /* R136 */ | ||
425 | 0x0000, /* R137 */ | ||
426 | 0x0000, /* R138 */ | ||
427 | 0x0000, /* R139 */ | ||
428 | 0x0312, /* R140 - GPIO Function Select 1 */ | ||
429 | 0x1003, /* R141 - GPIO Function Select 2 */ | ||
430 | 0x1331, /* R142 - GPIO Function Select 3 */ | ||
431 | 0x0003, /* R143 - GPIO Function Select 4 */ | ||
432 | 0x0000, /* R144 - Digitiser Control (1) */ | ||
433 | 0x0002, /* R145 - Digitiser Control (2) */ | ||
434 | 0x0000, /* R146 */ | ||
435 | 0x0000, /* R147 */ | ||
436 | 0x0000, /* R148 */ | ||
437 | 0x0000, /* R149 */ | ||
438 | 0x0000, /* R150 */ | ||
439 | 0x0000, /* R151 */ | ||
440 | 0x7000, /* R152 - AUX1 Readback */ | ||
441 | 0x7000, /* R153 - AUX2 Readback */ | ||
442 | 0x7000, /* R154 - AUX3 Readback */ | ||
443 | 0x7000, /* R155 - AUX4 Readback */ | ||
444 | 0x0000, /* R156 - USB Voltage Readback */ | ||
445 | 0x0000, /* R157 - LINE Voltage Readback */ | ||
446 | 0x0000, /* R158 - BATT Voltage Readback */ | ||
447 | 0x0000, /* R159 - Chip Temp Readback */ | ||
448 | 0x0000, /* R160 */ | ||
449 | 0x0000, /* R161 */ | ||
450 | 0x0000, /* R162 */ | ||
451 | 0x0000, /* R163 - Generic Comparator Control */ | ||
452 | 0x0000, /* R164 - Generic comparator 1 */ | ||
453 | 0x0000, /* R165 - Generic comparator 2 */ | ||
454 | 0x0000, /* R166 - Generic comparator 3 */ | ||
455 | 0x0000, /* R167 - Generic comparator 4 */ | ||
456 | 0xA00F, /* R168 - Battery Charger Control 1 */ | ||
457 | 0x0B06, /* R169 - Battery Charger Control 2 */ | ||
458 | 0x0000, /* R170 - Battery Charger Control 3 */ | ||
459 | 0x0000, /* R171 */ | ||
460 | 0x0000, /* R172 - Current Sink Driver A */ | ||
461 | 0x0000, /* R173 - CSA Flash control */ | ||
462 | 0x0000, /* R174 - Current Sink Driver B */ | ||
463 | 0x0000, /* R175 - CSB Flash control */ | ||
464 | 0x0000, /* R176 - DCDC/LDO requested */ | ||
465 | 0x002D, /* R177 - DCDC Active options */ | ||
466 | 0x0000, /* R178 - DCDC Sleep options */ | ||
467 | 0x0025, /* R179 - Power-check comparator */ | ||
468 | 0x0062, /* R180 - DCDC1 Control */ | ||
469 | 0x0400, /* R181 - DCDC1 Timeouts */ | ||
470 | 0x1006, /* R182 - DCDC1 Low Power */ | ||
471 | 0x0018, /* R183 - DCDC2 Control */ | ||
472 | 0x0000, /* R184 - DCDC2 Timeouts */ | ||
473 | 0x0000, /* R185 */ | ||
474 | 0x0026, /* R186 - DCDC3 Control */ | ||
475 | 0x0400, /* R187 - DCDC3 Timeouts */ | ||
476 | 0x0006, /* R188 - DCDC3 Low Power */ | ||
477 | 0x0062, /* R189 - DCDC4 Control */ | ||
478 | 0x0400, /* R190 - DCDC4 Timeouts */ | ||
479 | 0x0006, /* R191 - DCDC4 Low Power */ | ||
480 | 0x0008, /* R192 - DCDC5 Control */ | ||
481 | 0x0000, /* R193 - DCDC5 Timeouts */ | ||
482 | 0x0000, /* R194 */ | ||
483 | 0x0026, /* R195 - DCDC6 Control */ | ||
484 | 0x0800, /* R196 - DCDC6 Timeouts */ | ||
485 | 0x0006, /* R197 - DCDC6 Low Power */ | ||
486 | 0x0000, /* R198 */ | ||
487 | 0x0003, /* R199 - Limit Switch Control */ | ||
488 | 0x0006, /* R200 - LDO1 Control */ | ||
489 | 0x0400, /* R201 - LDO1 Timeouts */ | ||
490 | 0x001C, /* R202 - LDO1 Low Power */ | ||
491 | 0x0006, /* R203 - LDO2 Control */ | ||
492 | 0x0400, /* R204 - LDO2 Timeouts */ | ||
493 | 0x001C, /* R205 - LDO2 Low Power */ | ||
494 | 0x001B, /* R206 - LDO3 Control */ | ||
495 | 0x0000, /* R207 - LDO3 Timeouts */ | ||
496 | 0x001C, /* R208 - LDO3 Low Power */ | ||
497 | 0x001B, /* R209 - LDO4 Control */ | ||
498 | 0x0000, /* R210 - LDO4 Timeouts */ | ||
499 | 0x001C, /* R211 - LDO4 Low Power */ | ||
500 | 0x0000, /* R212 */ | ||
501 | 0x0000, /* R213 */ | ||
502 | 0x0000, /* R214 */ | ||
503 | 0x0000, /* R215 - VCC_FAULT Masks */ | ||
504 | 0x001F, /* R216 - Main Bandgap Control */ | ||
505 | 0x0000, /* R217 - OSC Control */ | ||
506 | 0x9000, /* R218 - RTC Tick Control */ | ||
507 | 0x0000, /* R219 */ | ||
508 | 0x4000, /* R220 - RAM BIST 1 */ | ||
509 | 0x0000, /* R221 */ | ||
510 | 0x0000, /* R222 */ | ||
511 | 0x0000, /* R223 */ | ||
512 | 0x0000, /* R224 */ | ||
513 | 0x0000, /* R225 - DCDC/LDO status */ | ||
514 | 0x0000, /* R226 */ | ||
515 | 0x0000, /* R227 */ | ||
516 | 0x0000, /* R228 */ | ||
517 | 0x0000, /* R229 */ | ||
518 | 0xE000, /* R230 - GPIO Pin Status */ | ||
519 | 0x0000, /* R231 */ | ||
520 | 0x0000, /* R232 */ | ||
521 | 0x0000, /* R233 */ | ||
522 | 0x0000, /* R234 */ | ||
523 | 0x0000, /* R235 */ | ||
524 | 0x0000, /* R236 */ | ||
525 | 0x0000, /* R237 */ | ||
526 | 0x0000, /* R238 */ | ||
527 | 0x0000, /* R239 */ | ||
528 | 0x0000, /* R240 */ | ||
529 | 0x0000, /* R241 */ | ||
530 | 0x0000, /* R242 */ | ||
531 | 0x0000, /* R243 */ | ||
532 | 0x0000, /* R244 */ | ||
533 | 0x0000, /* R245 */ | ||
534 | 0x0000, /* R246 */ | ||
535 | 0x0000, /* R247 */ | ||
536 | 0x0000, /* R248 */ | ||
537 | 0x0000, /* R249 */ | ||
538 | 0x0000, /* R250 */ | ||
539 | 0x0000, /* R251 */ | ||
540 | 0x0000, /* R252 */ | ||
541 | 0x0000, /* R253 */ | ||
542 | 0x0000, /* R254 */ | ||
543 | 0x0000, /* R255 */ | ||
544 | }; | ||
545 | #endif | ||
546 | |||
547 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2 | ||
548 | |||
549 | #undef WM8350_HAVE_CONFIG_MODE | ||
550 | #define WM8350_HAVE_CONFIG_MODE | ||
551 | |||
552 | const u16 wm8350_mode2_defaults[] = { | ||
553 | 0x17FF, /* R0 - Reset/ID */ | ||
554 | 0x1000, /* R1 - ID */ | ||
555 | 0x0000, /* R2 */ | ||
556 | 0x1002, /* R3 - System Control 1 */ | ||
557 | 0x0014, /* R4 - System Control 2 */ | ||
558 | 0x0000, /* R5 - System Hibernate */ | ||
559 | 0x8A00, /* R6 - Interface Control */ | ||
560 | 0x0000, /* R7 */ | ||
561 | 0x8000, /* R8 - Power mgmt (1) */ | ||
562 | 0x0000, /* R9 - Power mgmt (2) */ | ||
563 | 0x0000, /* R10 - Power mgmt (3) */ | ||
564 | 0x2000, /* R11 - Power mgmt (4) */ | ||
565 | 0x0E00, /* R12 - Power mgmt (5) */ | ||
566 | 0x0000, /* R13 - Power mgmt (6) */ | ||
567 | 0x0000, /* R14 - Power mgmt (7) */ | ||
568 | 0x0000, /* R15 */ | ||
569 | 0x0000, /* R16 - RTC Seconds/Minutes */ | ||
570 | 0x0100, /* R17 - RTC Hours/Day */ | ||
571 | 0x0101, /* R18 - RTC Date/Month */ | ||
572 | 0x1400, /* R19 - RTC Year */ | ||
573 | 0x0000, /* R20 - Alarm Seconds/Minutes */ | ||
574 | 0x0000, /* R21 - Alarm Hours/Day */ | ||
575 | 0x0000, /* R22 - Alarm Date/Month */ | ||
576 | 0x0320, /* R23 - RTC Time Control */ | ||
577 | 0x0000, /* R24 - System Interrupts */ | ||
578 | 0x0000, /* R25 - Interrupt Status 1 */ | ||
579 | 0x0000, /* R26 - Interrupt Status 2 */ | ||
580 | 0x0000, /* R27 - Power Up Interrupt Status */ | ||
581 | 0x0000, /* R28 - Under Voltage Interrupt status */ | ||
582 | 0x0000, /* R29 - Over Current Interrupt status */ | ||
583 | 0x0000, /* R30 - GPIO Interrupt Status */ | ||
584 | 0x0000, /* R31 - Comparator Interrupt Status */ | ||
585 | 0x3FFF, /* R32 - System Interrupts Mask */ | ||
586 | 0x0000, /* R33 - Interrupt Status 1 Mask */ | ||
587 | 0x0000, /* R34 - Interrupt Status 2 Mask */ | ||
588 | 0x0000, /* R35 - Power Up Interrupt Status Mask */ | ||
589 | 0x0000, /* R36 - Under Voltage Interrupt status Mask */ | ||
590 | 0x0000, /* R37 - Over Current Interrupt status Mask */ | ||
591 | 0x0000, /* R38 - GPIO Interrupt Status Mask */ | ||
592 | 0x0000, /* R39 - Comparator Interrupt Status Mask */ | ||
593 | 0x0040, /* R40 - Clock Control 1 */ | ||
594 | 0x0000, /* R41 - Clock Control 2 */ | ||
595 | 0x3B00, /* R42 - FLL Control 1 */ | ||
596 | 0x7086, /* R43 - FLL Control 2 */ | ||
597 | 0xC226, /* R44 - FLL Control 3 */ | ||
598 | 0x0000, /* R45 - FLL Control 4 */ | ||
599 | 0x0000, /* R46 */ | ||
600 | 0x0000, /* R47 */ | ||
601 | 0x0000, /* R48 - DAC Control */ | ||
602 | 0x0000, /* R49 */ | ||
603 | 0x00C0, /* R50 - DAC Digital Volume L */ | ||
604 | 0x00C0, /* R51 - DAC Digital Volume R */ | ||
605 | 0x0000, /* R52 */ | ||
606 | 0x0040, /* R53 - DAC LR Rate */ | ||
607 | 0x0000, /* R54 - DAC Clock Control */ | ||
608 | 0x0000, /* R55 */ | ||
609 | 0x0000, /* R56 */ | ||
610 | 0x0000, /* R57 */ | ||
611 | 0x4000, /* R58 - DAC Mute */ | ||
612 | 0x0000, /* R59 - DAC Mute Volume */ | ||
613 | 0x0000, /* R60 - DAC Side */ | ||
614 | 0x0000, /* R61 */ | ||
615 | 0x0000, /* R62 */ | ||
616 | 0x0000, /* R63 */ | ||
617 | 0x8000, /* R64 - ADC Control */ | ||
618 | 0x0000, /* R65 */ | ||
619 | 0x00C0, /* R66 - ADC Digital Volume L */ | ||
620 | 0x00C0, /* R67 - ADC Digital Volume R */ | ||
621 | 0x0000, /* R68 - ADC Divider */ | ||
622 | 0x0000, /* R69 */ | ||
623 | 0x0040, /* R70 - ADC LR Rate */ | ||
624 | 0x0000, /* R71 */ | ||
625 | 0x0303, /* R72 - Input Control */ | ||
626 | 0x0000, /* R73 - IN3 Input Control */ | ||
627 | 0x0000, /* R74 - Mic Bias Control */ | ||
628 | 0x0000, /* R75 */ | ||
629 | 0x0000, /* R76 - Output Control */ | ||
630 | 0x0000, /* R77 - Jack Detect */ | ||
631 | 0x0000, /* R78 - Anti Pop Control */ | ||
632 | 0x0000, /* R79 */ | ||
633 | 0x0040, /* R80 - Left Input Volume */ | ||
634 | 0x0040, /* R81 - Right Input Volume */ | ||
635 | 0x0000, /* R82 */ | ||
636 | 0x0000, /* R83 */ | ||
637 | 0x0000, /* R84 */ | ||
638 | 0x0000, /* R85 */ | ||
639 | 0x0000, /* R86 */ | ||
640 | 0x0000, /* R87 */ | ||
641 | 0x0800, /* R88 - Left Mixer Control */ | ||
642 | 0x1000, /* R89 - Right Mixer Control */ | ||
643 | 0x0000, /* R90 */ | ||
644 | 0x0000, /* R91 */ | ||
645 | 0x0000, /* R92 - OUT3 Mixer Control */ | ||
646 | 0x0000, /* R93 - OUT4 Mixer Control */ | ||
647 | 0x0000, /* R94 */ | ||
648 | 0x0000, /* R95 */ | ||
649 | 0x0000, /* R96 - Output Left Mixer Volume */ | ||
650 | 0x0000, /* R97 - Output Right Mixer Volume */ | ||
651 | 0x0000, /* R98 - Input Mixer Volume L */ | ||
652 | 0x0000, /* R99 - Input Mixer Volume R */ | ||
653 | 0x0000, /* R100 - Input Mixer Volume */ | ||
654 | 0x0000, /* R101 */ | ||
655 | 0x0000, /* R102 */ | ||
656 | 0x0000, /* R103 */ | ||
657 | 0x00E4, /* R104 - LOUT1 Volume */ | ||
658 | 0x00E4, /* R105 - ROUT1 Volume */ | ||
659 | 0x00E4, /* R106 - LOUT2 Volume */ | ||
660 | 0x02E4, /* R107 - ROUT2 Volume */ | ||
661 | 0x0000, /* R108 */ | ||
662 | 0x0000, /* R109 */ | ||
663 | 0x0000, /* R110 */ | ||
664 | 0x0000, /* R111 - BEEP Volume */ | ||
665 | 0x0A00, /* R112 - AI Formating */ | ||
666 | 0x0000, /* R113 - ADC DAC COMP */ | ||
667 | 0x0020, /* R114 - AI ADC Control */ | ||
668 | 0x0020, /* R115 - AI DAC Control */ | ||
669 | 0x0000, /* R116 - AIF Test */ | ||
670 | 0x0000, /* R117 */ | ||
671 | 0x0000, /* R118 */ | ||
672 | 0x0000, /* R119 */ | ||
673 | 0x0000, /* R120 */ | ||
674 | 0x0000, /* R121 */ | ||
675 | 0x0000, /* R122 */ | ||
676 | 0x0000, /* R123 */ | ||
677 | 0x0000, /* R124 */ | ||
678 | 0x0000, /* R125 */ | ||
679 | 0x0000, /* R126 */ | ||
680 | 0x0000, /* R127 */ | ||
681 | 0x1FFF, /* R128 - GPIO Debounce */ | ||
682 | 0x0000, /* R129 - GPIO Pin pull up Control */ | ||
683 | 0x03FC, /* R130 - GPIO Pull down Control */ | ||
684 | 0x0000, /* R131 - GPIO Interrupt Mode */ | ||
685 | 0x0000, /* R132 */ | ||
686 | 0x0000, /* R133 - GPIO Control */ | ||
687 | 0x08FB, /* R134 - GPIO Configuration (i/o) */ | ||
688 | 0x0CFE, /* R135 - GPIO Pin Polarity / Type */ | ||
689 | 0x0000, /* R136 */ | ||
690 | 0x0000, /* R137 */ | ||
691 | 0x0000, /* R138 */ | ||
692 | 0x0000, /* R139 */ | ||
693 | 0x0312, /* R140 - GPIO Function Select 1 */ | ||
694 | 0x0003, /* R141 - GPIO Function Select 2 */ | ||
695 | 0x2331, /* R142 - GPIO Function Select 3 */ | ||
696 | 0x0003, /* R143 - GPIO Function Select 4 */ | ||
697 | 0x0000, /* R144 - Digitiser Control (1) */ | ||
698 | 0x0002, /* R145 - Digitiser Control (2) */ | ||
699 | 0x0000, /* R146 */ | ||
700 | 0x0000, /* R147 */ | ||
701 | 0x0000, /* R148 */ | ||
702 | 0x0000, /* R149 */ | ||
703 | 0x0000, /* R150 */ | ||
704 | 0x0000, /* R151 */ | ||
705 | 0x7000, /* R152 - AUX1 Readback */ | ||
706 | 0x7000, /* R153 - AUX2 Readback */ | ||
707 | 0x7000, /* R154 - AUX3 Readback */ | ||
708 | 0x7000, /* R155 - AUX4 Readback */ | ||
709 | 0x0000, /* R156 - USB Voltage Readback */ | ||
710 | 0x0000, /* R157 - LINE Voltage Readback */ | ||
711 | 0x0000, /* R158 - BATT Voltage Readback */ | ||
712 | 0x0000, /* R159 - Chip Temp Readback */ | ||
713 | 0x0000, /* R160 */ | ||
714 | 0x0000, /* R161 */ | ||
715 | 0x0000, /* R162 */ | ||
716 | 0x0000, /* R163 - Generic Comparator Control */ | ||
717 | 0x0000, /* R164 - Generic comparator 1 */ | ||
718 | 0x0000, /* R165 - Generic comparator 2 */ | ||
719 | 0x0000, /* R166 - Generic comparator 3 */ | ||
720 | 0x0000, /* R167 - Generic comparator 4 */ | ||
721 | 0xA00F, /* R168 - Battery Charger Control 1 */ | ||
722 | 0x0B06, /* R169 - Battery Charger Control 2 */ | ||
723 | 0x0000, /* R170 - Battery Charger Control 3 */ | ||
724 | 0x0000, /* R171 */ | ||
725 | 0x0000, /* R172 - Current Sink Driver A */ | ||
726 | 0x0000, /* R173 - CSA Flash control */ | ||
727 | 0x0000, /* R174 - Current Sink Driver B */ | ||
728 | 0x0000, /* R175 - CSB Flash control */ | ||
729 | 0x0000, /* R176 - DCDC/LDO requested */ | ||
730 | 0x002D, /* R177 - DCDC Active options */ | ||
731 | 0x0000, /* R178 - DCDC Sleep options */ | ||
732 | 0x0025, /* R179 - Power-check comparator */ | ||
733 | 0x000E, /* R180 - DCDC1 Control */ | ||
734 | 0x0400, /* R181 - DCDC1 Timeouts */ | ||
735 | 0x1006, /* R182 - DCDC1 Low Power */ | ||
736 | 0x0018, /* R183 - DCDC2 Control */ | ||
737 | 0x0000, /* R184 - DCDC2 Timeouts */ | ||
738 | 0x0000, /* R185 */ | ||
739 | 0x002E, /* R186 - DCDC3 Control */ | ||
740 | 0x0800, /* R187 - DCDC3 Timeouts */ | ||
741 | 0x0006, /* R188 - DCDC3 Low Power */ | ||
742 | 0x000E, /* R189 - DCDC4 Control */ | ||
743 | 0x0800, /* R190 - DCDC4 Timeouts */ | ||
744 | 0x0006, /* R191 - DCDC4 Low Power */ | ||
745 | 0x0008, /* R192 - DCDC5 Control */ | ||
746 | 0x0000, /* R193 - DCDC5 Timeouts */ | ||
747 | 0x0000, /* R194 */ | ||
748 | 0x0026, /* R195 - DCDC6 Control */ | ||
749 | 0x0C00, /* R196 - DCDC6 Timeouts */ | ||
750 | 0x0006, /* R197 - DCDC6 Low Power */ | ||
751 | 0x0000, /* R198 */ | ||
752 | 0x0003, /* R199 - Limit Switch Control */ | ||
753 | 0x001A, /* R200 - LDO1 Control */ | ||
754 | 0x0800, /* R201 - LDO1 Timeouts */ | ||
755 | 0x001C, /* R202 - LDO1 Low Power */ | ||
756 | 0x0010, /* R203 - LDO2 Control */ | ||
757 | 0x0800, /* R204 - LDO2 Timeouts */ | ||
758 | 0x001C, /* R205 - LDO2 Low Power */ | ||
759 | 0x000A, /* R206 - LDO3 Control */ | ||
760 | 0x0C00, /* R207 - LDO3 Timeouts */ | ||
761 | 0x001C, /* R208 - LDO3 Low Power */ | ||
762 | 0x001A, /* R209 - LDO4 Control */ | ||
763 | 0x0800, /* R210 - LDO4 Timeouts */ | ||
764 | 0x001C, /* R211 - LDO4 Low Power */ | ||
765 | 0x0000, /* R212 */ | ||
766 | 0x0000, /* R213 */ | ||
767 | 0x0000, /* R214 */ | ||
768 | 0x0000, /* R215 - VCC_FAULT Masks */ | ||
769 | 0x001F, /* R216 - Main Bandgap Control */ | ||
770 | 0x0000, /* R217 - OSC Control */ | ||
771 | 0x9000, /* R218 - RTC Tick Control */ | ||
772 | 0x0000, /* R219 */ | ||
773 | 0x4000, /* R220 - RAM BIST 1 */ | ||
774 | 0x0000, /* R221 */ | ||
775 | 0x0000, /* R222 */ | ||
776 | 0x0000, /* R223 */ | ||
777 | 0x0000, /* R224 */ | ||
778 | 0x0000, /* R225 - DCDC/LDO status */ | ||
779 | 0x0000, /* R226 */ | ||
780 | 0x0000, /* R227 */ | ||
781 | 0x0000, /* R228 */ | ||
782 | 0x0000, /* R229 */ | ||
783 | 0xE000, /* R230 - GPIO Pin Status */ | ||
784 | 0x0000, /* R231 */ | ||
785 | 0x0000, /* R232 */ | ||
786 | 0x0000, /* R233 */ | ||
787 | 0x0000, /* R234 */ | ||
788 | 0x0000, /* R235 */ | ||
789 | 0x0000, /* R236 */ | ||
790 | 0x0000, /* R237 */ | ||
791 | 0x0000, /* R238 */ | ||
792 | 0x0000, /* R239 */ | ||
793 | 0x0000, /* R240 */ | ||
794 | 0x0000, /* R241 */ | ||
795 | 0x0000, /* R242 */ | ||
796 | 0x0000, /* R243 */ | ||
797 | 0x0000, /* R244 */ | ||
798 | 0x0000, /* R245 */ | ||
799 | 0x0000, /* R246 */ | ||
800 | 0x0000, /* R247 */ | ||
801 | 0x0000, /* R248 */ | ||
802 | 0x0000, /* R249 */ | ||
803 | 0x0000, /* R250 */ | ||
804 | 0x0000, /* R251 */ | ||
805 | 0x0000, /* R252 */ | ||
806 | 0x0000, /* R253 */ | ||
807 | 0x0000, /* R254 */ | ||
808 | 0x0000, /* R255 */ | ||
809 | }; | ||
810 | #endif | ||
811 | |||
812 | #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3 | ||
813 | |||
814 | #undef WM8350_HAVE_CONFIG_MODE | ||
815 | #define WM8350_HAVE_CONFIG_MODE | ||
816 | |||
817 | const u16 wm8350_mode3_defaults[] = { | ||
818 | 0x17FF, /* R0 - Reset/ID */ | ||
819 | 0x1000, /* R1 - ID */ | ||
820 | 0x0000, /* R2 */ | ||
821 | 0x1000, /* R3 - System Control 1 */ | ||
822 | 0x0004, /* R4 - System Control 2 */ | ||
823 | 0x0000, /* R5 - System Hibernate */ | ||
824 | 0x8A00, /* R6 - Interface Control */ | ||
825 | 0x0000, /* R7 */ | ||
826 | 0x8000, /* R8 - Power mgmt (1) */ | ||
827 | 0x0000, /* R9 - Power mgmt (2) */ | ||
828 | 0x0000, /* R10 - Power mgmt (3) */ | ||
829 | 0x2000, /* R11 - Power mgmt (4) */ | ||
830 | 0x0E00, /* R12 - Power mgmt (5) */ | ||
831 | 0x0000, /* R13 - Power mgmt (6) */ | ||
832 | 0x0000, /* R14 - Power mgmt (7) */ | ||
833 | 0x0000, /* R15 */ | ||
834 | 0x0000, /* R16 - RTC Seconds/Minutes */ | ||
835 | 0x0100, /* R17 - RTC Hours/Day */ | ||
836 | 0x0101, /* R18 - RTC Date/Month */ | ||
837 | 0x1400, /* R19 - RTC Year */ | ||
838 | 0x0000, /* R20 - Alarm Seconds/Minutes */ | ||
839 | 0x0000, /* R21 - Alarm Hours/Day */ | ||
840 | 0x0000, /* R22 - Alarm Date/Month */ | ||
841 | 0x0320, /* R23 - RTC Time Control */ | ||
842 | 0x0000, /* R24 - System Interrupts */ | ||
843 | 0x0000, /* R25 - Interrupt Status 1 */ | ||
844 | 0x0000, /* R26 - Interrupt Status 2 */ | ||
845 | 0x0000, /* R27 - Power Up Interrupt Status */ | ||
846 | 0x0000, /* R28 - Under Voltage Interrupt status */ | ||
847 | 0x0000, /* R29 - Over Current Interrupt status */ | ||
848 | 0x0000, /* R30 - GPIO Interrupt Status */ | ||
849 | 0x0000, /* R31 - Comparator Interrupt Status */ | ||
850 | 0x3FFF, /* R32 - System Interrupts Mask */ | ||
851 | 0x0000, /* R33 - Interrupt Status 1 Mask */ | ||
852 | 0x0000, /* R34 - Interrupt Status 2 Mask */ | ||
853 | 0x0000, /* R35 - Power Up Interrupt Status Mask */ | ||
854 | 0x0000, /* R36 - Under Voltage Interrupt status Mask */ | ||
855 | 0x0000, /* R37 - Over Current Interrupt status Mask */ | ||
856 | 0x0000, /* R38 - GPIO Interrupt Status Mask */ | ||
857 | 0x0000, /* R39 - Comparator Interrupt Status Mask */ | ||
858 | 0x0040, /* R40 - Clock Control 1 */ | ||
859 | 0x0000, /* R41 - Clock Control 2 */ | ||
860 | 0x3B00, /* R42 - FLL Control 1 */ | ||
861 | 0x7086, /* R43 - FLL Control 2 */ | ||
862 | 0xC226, /* R44 - FLL Control 3 */ | ||
863 | 0x0000, /* R45 - FLL Control 4 */ | ||
864 | 0x0000, /* R46 */ | ||
865 | 0x0000, /* R47 */ | ||
866 | 0x0000, /* R48 - DAC Control */ | ||
867 | 0x0000, /* R49 */ | ||
868 | 0x00C0, /* R50 - DAC Digital Volume L */ | ||
869 | 0x00C0, /* R51 - DAC Digital Volume R */ | ||
870 | 0x0000, /* R52 */ | ||
871 | 0x0040, /* R53 - DAC LR Rate */ | ||
872 | 0x0000, /* R54 - DAC Clock Control */ | ||
873 | 0x0000, /* R55 */ | ||
874 | 0x0000, /* R56 */ | ||
875 | 0x0000, /* R57 */ | ||
876 | 0x4000, /* R58 - DAC Mute */ | ||
877 | 0x0000, /* R59 - DAC Mute Volume */ | ||
878 | 0x0000, /* R60 - DAC Side */ | ||
879 | 0x0000, /* R61 */ | ||
880 | 0x0000, /* R62 */ | ||
881 | 0x0000, /* R63 */ | ||
882 | 0x8000, /* R64 - ADC Control */ | ||
883 | 0x0000, /* R65 */ | ||
884 | 0x00C0, /* R66 - ADC Digital Volume L */ | ||
885 | 0x00C0, /* R67 - ADC Digital Volume R */ | ||
886 | 0x0000, /* R68 - ADC Divider */ | ||
887 | 0x0000, /* R69 */ | ||
888 | 0x0040, /* R70 - ADC LR Rate */ | ||
889 | 0x0000, /* R71 */ | ||
890 | 0x0303, /* R72 - Input Control */ | ||
891 | 0x0000, /* R73 - IN3 Input Control */ | ||
892 | 0x0000, /* R74 - Mic Bias Control */ | ||
893 | 0x0000, /* R75 */ | ||
894 | 0x0000, /* R76 - Output Control */ | ||
895 | 0x0000, /* R77 - Jack Detect */ | ||
896 | 0x0000, /* R78 - Anti Pop Control */ | ||
897 | 0x0000, /* R79 */ | ||
898 | 0x0040, /* R80 - Left Input Volume */ | ||
899 | 0x0040, /* R81 - Right Input Volume */ | ||
900 | 0x0000, /* R82 */ | ||
901 | 0x0000, /* R83 */ | ||
902 | 0x0000, /* R84 */ | ||
903 | 0x0000, /* R85 */ | ||
904 | 0x0000, /* R86 */ | ||
905 | 0x0000, /* R87 */ | ||
906 | 0x0800, /* R88 - Left Mixer Control */ | ||
907 | 0x1000, /* R89 - Right Mixer Control */ | ||
908 | 0x0000, /* R90 */ | ||
909 | 0x0000, /* R91 */ | ||
910 | 0x0000, /* R92 - OUT3 Mixer Control */ | ||
911 | 0x0000, /* R93 - OUT4 Mixer Control */ | ||
912 | 0x0000, /* R94 */ | ||
913 | 0x0000, /* R95 */ | ||
914 | 0x0000, /* R96 - Output Left Mixer Volume */ | ||
915 | 0x0000, /* R97 - Output Right Mixer Volume */ | ||
916 | 0x0000, /* R98 - Input Mixer Volume L */ | ||
917 | 0x0000, /* R99 - Input Mixer Volume R */ | ||
918 | 0x0000, /* R100 - Input Mixer Volume */ | ||
919 | 0x0000, /* R101 */ | ||
920 | 0x0000, /* R102 */ | ||
921 | 0x0000, /* R103 */ | ||
922 | 0x00E4, /* R104 - LOUT1 Volume */ | ||
923 | 0x00E4, /* R105 - ROUT1 Volume */ | ||
924 | 0x00E4, /* R106 - LOUT2 Volume */ | ||
925 | 0x02E4, /* R107 - ROUT2 Volume */ | ||
926 | 0x0000, /* R108 */ | ||
927 | 0x0000, /* R109 */ | ||
928 | 0x0000, /* R110 */ | ||
929 | 0x0000, /* R111 - BEEP Volume */ | ||
930 | 0x0A00, /* R112 - AI Formating */ | ||
931 | 0x0000, /* R113 - ADC DAC COMP */ | ||
932 | 0x0020, /* R114 - AI ADC Control */ | ||
933 | 0x0020, /* R115 - AI DAC Control */ | ||
934 | 0x0000, /* R116 - AIF Test */ | ||
935 | 0x0000, /* R117 */ | ||
936 | 0x0000, /* R118 */ | ||
937 | 0x0000, /* R119 */ | ||
938 | 0x0000, /* R120 */ | ||
939 | 0x0000, /* R121 */ | ||
940 | 0x0000, /* R122 */ | ||
941 | 0x0000, /* R123 */ | ||
942 | 0x0000, /* R124 */ | ||
943 | 0x0000, /* R125 */ | ||
944 | 0x0000, /* R126 */ | ||
945 | 0x0000, /* R127 */ | ||
946 | 0x1FFF, /* R128 - GPIO Debounce */ | ||
947 | 0x0000, /* R129 - GPIO Pin pull up Control */ | ||
948 | 0x03FC, /* R130 - GPIO Pull down Control */ | ||
949 | 0x0000, /* R131 - GPIO Interrupt Mode */ | ||
950 | 0x0000, /* R132 */ | ||
951 | 0x0000, /* R133 - GPIO Control */ | ||
952 | 0x0A7B, /* R134 - GPIO Configuration (i/o) */ | ||
953 | 0x06FE, /* R135 - GPIO Pin Polarity / Type */ | ||
954 | 0x0000, /* R136 */ | ||
955 | 0x0000, /* R137 */ | ||
956 | 0x0000, /* R138 */ | ||
957 | 0x0000, /* R139 */ | ||
958 | 0x1312, /* R140 - GPIO Function Select 1 */ | ||
959 | 0x1030, /* R141 - GPIO Function Select 2 */ | ||
960 | 0x2231, /* R142 - GPIO Function Select 3 */ | ||
961 | 0x0003, /* R143 - GPIO Function Select 4 */ | ||
962 | 0x0000, /* R144 - Digitiser Control (1) */ | ||
963 | 0x0002, /* R145 - Digitiser Control (2) */ | ||
964 | 0x0000, /* R146 */ | ||
965 | 0x0000, /* R147 */ | ||
966 | 0x0000, /* R148 */ | ||
967 | 0x0000, /* R149 */ | ||
968 | 0x0000, /* R150 */ | ||
969 | 0x0000, /* R151 */ | ||
970 | 0x7000, /* R152 - AUX1 Readback */ | ||
971 | 0x7000, /* R153 - AUX2 Readback */ | ||
972 | 0x7000, /* R154 - AUX3 Readback */ | ||
973 | 0x7000, /* R155 - AUX4 Readback */ | ||
974 | 0x0000, /* R156 - USB Voltage Readback */ | ||
975 | 0x0000, /* R157 - LINE Voltage Readback */ | ||
976 | 0x0000, /* R158 - BATT Voltage Readback */ | ||
977 | 0x0000, /* R159 - Chip Temp Readback */ | ||
978 | 0x0000, /* R160 */ | ||
979 | 0x0000, /* R161 */ | ||
980 | 0x0000, /* R162 */ | ||
981 | 0x0000, /* R163 - Generic Comparator Control */ | ||
982 | 0x0000, /* R164 - Generic comparator 1 */ | ||
983 | 0x0000, /* R165 - Generic comparator 2 */ | ||
984 | 0x0000, /* R166 - Generic comparator 3 */ | ||
985 | 0x0000, /* R167 - Generic comparator 4 */ | ||
986 | 0xA00F, /* R168 - Battery Charger Control 1 */ | ||
987 | 0x0B06, /* R169 - Battery Charger Control 2 */ | ||
988 | 0x0000, /* R170 - Battery Charger Control 3 */ | ||
989 | 0x0000, /* R171 */ | ||
990 | 0x0000, /* R172 - Current Sink Driver A */ | ||
991 | 0x0000, /* R173 - CSA Flash control */ | ||
992 | 0x0000, /* R174 - Current Sink Driver B */ | ||
993 | 0x0000, /* R175 - CSB Flash control */ | ||
994 | 0x0000, /* R176 - DCDC/LDO requested */ | ||
995 | 0x002D, /* R177 - DCDC Active options */ | ||
996 | 0x0000, /* R178 - DCDC Sleep options */ | ||
997 | 0x0025, /* R179 - Power-check comparator */ | ||
998 | 0x000E, /* R180 - DCDC1 Control */ | ||
999 | 0x0400, /* R181 - DCDC1 Timeouts */ | ||
1000 | 0x1006, /* R182 - DCDC1 Low Power */ | ||
1001 | 0x0018, /* R183 - DCDC2 Control */ | ||
1002 | 0x0000, /* R184 - DCDC2 Timeouts */ | ||
1003 | 0x0000, /* R185 */ | ||
1004 | 0x000E, /* R186 - DCDC3 Control */ | ||
1005 | 0x0400, /* R187 - DCDC3 Timeouts */ | ||
1006 | 0x0006, /* R188 - DCDC3 Low Power */ | ||
1007 | 0x0026, /* R189 - DCDC4 Control */ | ||
1008 | 0x0400, /* R190 - DCDC4 Timeouts */ | ||
1009 | 0x0006, /* R191 - DCDC4 Low Power */ | ||
1010 | 0x0008, /* R192 - DCDC5 Control */ | ||
1011 | 0x0000, /* R193 - DCDC5 Timeouts */ | ||
1012 | 0x0000, /* R194 */ | ||
1013 | 0x0026, /* R195 - DCDC6 Control */ | ||
1014 | 0x0400, /* R196 - DCDC6 Timeouts */ | ||
1015 | 0x0006, /* R197 - DCDC6 Low Power */ | ||
1016 | 0x0000, /* R198 */ | ||
1017 | 0x0003, /* R199 - Limit Switch Control */ | ||
1018 | 0x001C, /* R200 - LDO1 Control */ | ||
1019 | 0x0000, /* R201 - LDO1 Timeouts */ | ||
1020 | 0x001C, /* R202 - LDO1 Low Power */ | ||
1021 | 0x001C, /* R203 - LDO2 Control */ | ||
1022 | 0x0400, /* R204 - LDO2 Timeouts */ | ||
1023 | 0x001C, /* R205 - LDO2 Low Power */ | ||
1024 | 0x001C, /* R206 - LDO3 Control */ | ||
1025 | 0x0400, /* R207 - LDO3 Timeouts */ | ||
1026 | 0x001C, /* R208 - LDO3 Low Power */ | ||
1027 | 0x001F, /* R209 - LDO4 Control */ | ||
1028 | 0x0400, /* R210 - LDO4 Timeouts */ | ||
1029 | 0x001C, /* R211 - LDO4 Low Power */ | ||
1030 | 0x0000, /* R212 */ | ||
1031 | 0x0000, /* R213 */ | ||
1032 | 0x0000, /* R214 */ | ||
1033 | 0x0000, /* R215 - VCC_FAULT Masks */ | ||
1034 | 0x001F, /* R216 - Main Bandgap Control */ | ||
1035 | 0x0000, /* R217 - OSC Control */ | ||
1036 | 0x9000, /* R218 - RTC Tick Control */ | ||
1037 | 0x0000, /* R219 */ | ||
1038 | 0x4000, /* R220 - RAM BIST 1 */ | ||
1039 | 0x0000, /* R221 */ | ||
1040 | 0x0000, /* R222 */ | ||
1041 | 0x0000, /* R223 */ | ||
1042 | 0x0000, /* R224 */ | ||
1043 | 0x0000, /* R225 - DCDC/LDO status */ | ||
1044 | 0x0000, /* R226 */ | ||
1045 | 0x0000, /* R227 */ | ||
1046 | 0x0000, /* R228 */ | ||
1047 | 0x0000, /* R229 */ | ||
1048 | 0xE000, /* R230 - GPIO Pin Status */ | ||
1049 | 0x0000, /* R231 */ | ||
1050 | 0x0000, /* R232 */ | ||
1051 | 0x0000, /* R233 */ | ||
1052 | 0x0000, /* R234 */ | ||
1053 | 0x0000, /* R235 */ | ||
1054 | 0x0000, /* R236 */ | ||
1055 | 0x0000, /* R237 */ | ||
1056 | 0x0000, /* R238 */ | ||
1057 | 0x0000, /* R239 */ | ||
1058 | 0x0000, /* R240 */ | ||
1059 | 0x0000, /* R241 */ | ||
1060 | 0x0000, /* R242 */ | ||
1061 | 0x0000, /* R243 */ | ||
1062 | 0x0000, /* R244 */ | ||
1063 | 0x0000, /* R245 */ | ||
1064 | 0x0000, /* R246 */ | ||
1065 | 0x0000, /* R247 */ | ||
1066 | 0x0000, /* R248 */ | ||
1067 | 0x0000, /* R249 */ | ||
1068 | 0x0000, /* R250 */ | ||
1069 | 0x0000, /* R251 */ | ||
1070 | 0x0000, /* R252 */ | ||
1071 | 0x0000, /* R253 */ | ||
1072 | 0x0000, /* R254 */ | ||
1073 | 0x0000, /* R255 */ | ||
1074 | }; | ||
1075 | #endif | ||
1076 | |||
1077 | /* The register defaults for the config mode used must be compiled in but | ||
1078 | * due to the impact on kernel size it is possible to disable | ||
1079 | */ | ||
1080 | #ifndef WM8350_HAVE_CONFIG_MODE | ||
1081 | #warning No WM8350 config modes supported - select at least one of the | ||
1082 | #warning MFD_WM8350_CONFIG_MODE_n options from the board driver. | ||
1083 | #endif | ||
1084 | |||
1085 | /* | ||
1086 | * Access masks. | ||
1087 | */ | ||
1088 | |||
1089 | const struct wm8350_reg_access wm8350_reg_io_map[] = { | ||
1090 | /* read write volatile */ | ||
1091 | { 0xFFFF, 0xFFFF, 0xFFFF }, /* R0 - Reset/ID */ | ||
1092 | { 0x7CFF, 0x0C00, 0x7FFF }, /* R1 - ID */ | ||
1093 | { 0x0000, 0x0000, 0x0000 }, /* R2 */ | ||
1094 | { 0xBE3B, 0xBE3B, 0x8000 }, /* R3 - System Control 1 */ | ||
1095 | { 0xFCF7, 0xFCF7, 0xF800 }, /* R4 - System Control 2 */ | ||
1096 | { 0x80FF, 0x80FF, 0x8000 }, /* R5 - System Hibernate */ | ||
1097 | { 0xFB0E, 0xFB0E, 0x0000 }, /* R6 - Interface Control */ | ||
1098 | { 0x0000, 0x0000, 0x0000 }, /* R7 */ | ||
1099 | { 0xE537, 0xE537, 0xFFFF }, /* R8 - Power mgmt (1) */ | ||
1100 | { 0x0FF3, 0x0FF3, 0xFFFF }, /* R9 - Power mgmt (2) */ | ||
1101 | { 0x008F, 0x008F, 0xFFFF }, /* R10 - Power mgmt (3) */ | ||
1102 | { 0x6D3C, 0x6D3C, 0xFFFF }, /* R11 - Power mgmt (4) */ | ||
1103 | { 0x1F8F, 0x1F8F, 0xFFFF }, /* R12 - Power mgmt (5) */ | ||
1104 | { 0x8F3F, 0x8F3F, 0xFFFF }, /* R13 - Power mgmt (6) */ | ||
1105 | { 0x0003, 0x0003, 0xFFFF }, /* R14 - Power mgmt (7) */ | ||
1106 | { 0x0000, 0x0000, 0x0000 }, /* R15 */ | ||
1107 | { 0x7F7F, 0x7F7F, 0xFFFF }, /* R16 - RTC Seconds/Minutes */ | ||
1108 | { 0x073F, 0x073F, 0xFFFF }, /* R17 - RTC Hours/Day */ | ||
1109 | { 0x1F3F, 0x1F3F, 0xFFFF }, /* R18 - RTC Date/Month */ | ||
1110 | { 0x3FFF, 0x00FF, 0xFFFF }, /* R19 - RTC Year */ | ||
1111 | { 0x7F7F, 0x7F7F, 0x0000 }, /* R20 - Alarm Seconds/Minutes */ | ||
1112 | { 0x0F3F, 0x0F3F, 0x0000 }, /* R21 - Alarm Hours/Day */ | ||
1113 | { 0x1F3F, 0x1F3F, 0x0000 }, /* R22 - Alarm Date/Month */ | ||
1114 | { 0xEF7F, 0xEA7F, 0xFFFF }, /* R23 - RTC Time Control */ | ||
1115 | { 0x3BFF, 0x0000, 0xFFFF }, /* R24 - System Interrupts */ | ||
1116 | { 0xFEE7, 0x0000, 0xFFFF }, /* R25 - Interrupt Status 1 */ | ||
1117 | { 0x35FF, 0x0000, 0xFFFF }, /* R26 - Interrupt Status 2 */ | ||
1118 | { 0x0F3F, 0x0000, 0xFFFF }, /* R27 - Power Up Interrupt Status */ | ||
1119 | { 0x0F3F, 0x0000, 0xFFFF }, /* R28 - Under Voltage Interrupt status */ | ||
1120 | { 0x8000, 0x0000, 0xFFFF }, /* R29 - Over Current Interrupt status */ | ||
1121 | { 0x1FFF, 0x0000, 0xFFFF }, /* R30 - GPIO Interrupt Status */ | ||
1122 | { 0xEF7F, 0x0000, 0xFFFF }, /* R31 - Comparator Interrupt Status */ | ||
1123 | { 0x3FFF, 0x3FFF, 0x0000 }, /* R32 - System Interrupts Mask */ | ||
1124 | { 0xFEE7, 0xFEE7, 0x0000 }, /* R33 - Interrupt Status 1 Mask */ | ||
1125 | { 0xF5FF, 0xF5FF, 0x0000 }, /* R34 - Interrupt Status 2 Mask */ | ||
1126 | { 0x0F3F, 0x0F3F, 0x0000 }, /* R35 - Power Up Interrupt Status Mask */ | ||
1127 | { 0x0F3F, 0x0F3F, 0x0000 }, /* R36 - Under Voltage Int status Mask */ | ||
1128 | { 0x8000, 0x8000, 0x0000 }, /* R37 - Over Current Int status Mask */ | ||
1129 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R38 - GPIO Interrupt Status Mask */ | ||
1130 | { 0xEF7F, 0xEF7F, 0x0000 }, /* R39 - Comparator IntStatus Mask */ | ||
1131 | { 0xC9F7, 0xC9F7, 0xFFFF }, /* R40 - Clock Control 1 */ | ||
1132 | { 0x8001, 0x8001, 0x0000 }, /* R41 - Clock Control 2 */ | ||
1133 | { 0xFFF7, 0xFFF7, 0xFFFF }, /* R42 - FLL Control 1 */ | ||
1134 | { 0xFBFF, 0xFBFF, 0x0000 }, /* R43 - FLL Control 2 */ | ||
1135 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R44 - FLL Control 3 */ | ||
1136 | { 0x0033, 0x0033, 0x0000 }, /* R45 - FLL Control 4 */ | ||
1137 | { 0x0000, 0x0000, 0x0000 }, /* R46 */ | ||
1138 | { 0x0000, 0x0000, 0x0000 }, /* R47 */ | ||
1139 | { 0x3033, 0x3033, 0x0000 }, /* R48 - DAC Control */ | ||
1140 | { 0x0000, 0x0000, 0x0000 }, /* R49 */ | ||
1141 | { 0x81FF, 0x81FF, 0xFFFF }, /* R50 - DAC Digital Volume L */ | ||
1142 | { 0x81FF, 0x81FF, 0xFFFF }, /* R51 - DAC Digital Volume R */ | ||
1143 | { 0x0000, 0x0000, 0x0000 }, /* R52 */ | ||
1144 | { 0x0FFF, 0x0FFF, 0xFFFF }, /* R53 - DAC LR Rate */ | ||
1145 | { 0x0017, 0x0017, 0x0000 }, /* R54 - DAC Clock Control */ | ||
1146 | { 0x0000, 0x0000, 0x0000 }, /* R55 */ | ||
1147 | { 0x0000, 0x0000, 0x0000 }, /* R56 */ | ||
1148 | { 0x0000, 0x0000, 0x0000 }, /* R57 */ | ||
1149 | { 0x4000, 0x4000, 0x0000 }, /* R58 - DAC Mute */ | ||
1150 | { 0x7000, 0x7000, 0x0000 }, /* R59 - DAC Mute Volume */ | ||
1151 | { 0x3C00, 0x3C00, 0x0000 }, /* R60 - DAC Side */ | ||
1152 | { 0x0000, 0x0000, 0x0000 }, /* R61 */ | ||
1153 | { 0x0000, 0x0000, 0x0000 }, /* R62 */ | ||
1154 | { 0x0000, 0x0000, 0x0000 }, /* R63 */ | ||
1155 | { 0x8303, 0x8303, 0xFFFF }, /* R64 - ADC Control */ | ||
1156 | { 0x0000, 0x0000, 0x0000 }, /* R65 */ | ||
1157 | { 0x81FF, 0x81FF, 0xFFFF }, /* R66 - ADC Digital Volume L */ | ||
1158 | { 0x81FF, 0x81FF, 0xFFFF }, /* R67 - ADC Digital Volume R */ | ||
1159 | { 0x0FFF, 0x0FFF, 0x0000 }, /* R68 - ADC Divider */ | ||
1160 | { 0x0000, 0x0000, 0x0000 }, /* R69 */ | ||
1161 | { 0x0FFF, 0x0FFF, 0xFFFF }, /* R70 - ADC LR Rate */ | ||
1162 | { 0x0000, 0x0000, 0x0000 }, /* R71 */ | ||
1163 | { 0x0707, 0x0707, 0xFFFF }, /* R72 - Input Control */ | ||
1164 | { 0xC0C0, 0xC0C0, 0xFFFF }, /* R73 - IN3 Input Control */ | ||
1165 | { 0xC09F, 0xC09F, 0xFFFF }, /* R74 - Mic Bias Control */ | ||
1166 | { 0x0000, 0x0000, 0x0000 }, /* R75 */ | ||
1167 | { 0x0F15, 0x0F15, 0xFFFF }, /* R76 - Output Control */ | ||
1168 | { 0xC000, 0xC000, 0xFFFF }, /* R77 - Jack Detect */ | ||
1169 | { 0x03FF, 0x03FF, 0x0000 }, /* R78 - Anti Pop Control */ | ||
1170 | { 0x0000, 0x0000, 0x0000 }, /* R79 */ | ||
1171 | { 0xE1FC, 0xE1FC, 0x8000 }, /* R80 - Left Input Volume */ | ||
1172 | { 0xE1FC, 0xE1FC, 0x8000 }, /* R81 - Right Input Volume */ | ||
1173 | { 0x0000, 0x0000, 0x0000 }, /* R82 */ | ||
1174 | { 0x0000, 0x0000, 0x0000 }, /* R83 */ | ||
1175 | { 0x0000, 0x0000, 0x0000 }, /* R84 */ | ||
1176 | { 0x0000, 0x0000, 0x0000 }, /* R85 */ | ||
1177 | { 0x0000, 0x0000, 0x0000 }, /* R86 */ | ||
1178 | { 0x0000, 0x0000, 0x0000 }, /* R87 */ | ||
1179 | { 0x9807, 0x9807, 0xFFFF }, /* R88 - Left Mixer Control */ | ||
1180 | { 0x980B, 0x980B, 0xFFFF }, /* R89 - Right Mixer Control */ | ||
1181 | { 0x0000, 0x0000, 0x0000 }, /* R90 */ | ||
1182 | { 0x0000, 0x0000, 0x0000 }, /* R91 */ | ||
1183 | { 0x8909, 0x8909, 0xFFFF }, /* R92 - OUT3 Mixer Control */ | ||
1184 | { 0x9E07, 0x9E07, 0xFFFF }, /* R93 - OUT4 Mixer Control */ | ||
1185 | { 0x0000, 0x0000, 0x0000 }, /* R94 */ | ||
1186 | { 0x0000, 0x0000, 0x0000 }, /* R95 */ | ||
1187 | { 0x0EEE, 0x0EEE, 0x0000 }, /* R96 - Output Left Mixer Volume */ | ||
1188 | { 0xE0EE, 0xE0EE, 0x0000 }, /* R97 - Output Right Mixer Volume */ | ||
1189 | { 0x0E0F, 0x0E0F, 0x0000 }, /* R98 - Input Mixer Volume L */ | ||
1190 | { 0xE0E1, 0xE0E1, 0x0000 }, /* R99 - Input Mixer Volume R */ | ||
1191 | { 0x800E, 0x800E, 0x0000 }, /* R100 - Input Mixer Volume */ | ||
1192 | { 0x0000, 0x0000, 0x0000 }, /* R101 */ | ||
1193 | { 0x0000, 0x0000, 0x0000 }, /* R102 */ | ||
1194 | { 0x0000, 0x0000, 0x0000 }, /* R103 */ | ||
1195 | { 0xE1FC, 0xE1FC, 0xFFFF }, /* R104 - LOUT1 Volume */ | ||
1196 | { 0xE1FC, 0xE1FC, 0xFFFF }, /* R105 - ROUT1 Volume */ | ||
1197 | { 0xE1FC, 0xE1FC, 0xFFFF }, /* R106 - LOUT2 Volume */ | ||
1198 | { 0xE7FC, 0xE7FC, 0xFFFF }, /* R107 - ROUT2 Volume */ | ||
1199 | { 0x0000, 0x0000, 0x0000 }, /* R108 */ | ||
1200 | { 0x0000, 0x0000, 0x0000 }, /* R109 */ | ||
1201 | { 0x0000, 0x0000, 0x0000 }, /* R110 */ | ||
1202 | { 0x80E0, 0x80E0, 0xFFFF }, /* R111 - BEEP Volume */ | ||
1203 | { 0xBF00, 0xBF00, 0x0000 }, /* R112 - AI Formating */ | ||
1204 | { 0x00F1, 0x00F1, 0x0000 }, /* R113 - ADC DAC COMP */ | ||
1205 | { 0x00F8, 0x00F8, 0x0000 }, /* R114 - AI ADC Control */ | ||
1206 | { 0x40FB, 0x40FB, 0x0000 }, /* R115 - AI DAC Control */ | ||
1207 | { 0x7C30, 0x7C30, 0x0000 }, /* R116 - AIF Test */ | ||
1208 | { 0x0000, 0x0000, 0x0000 }, /* R117 */ | ||
1209 | { 0x0000, 0x0000, 0x0000 }, /* R118 */ | ||
1210 | { 0x0000, 0x0000, 0x0000 }, /* R119 */ | ||
1211 | { 0x0000, 0x0000, 0x0000 }, /* R120 */ | ||
1212 | { 0x0000, 0x0000, 0x0000 }, /* R121 */ | ||
1213 | { 0x0000, 0x0000, 0x0000 }, /* R122 */ | ||
1214 | { 0x0000, 0x0000, 0x0000 }, /* R123 */ | ||
1215 | { 0x0000, 0x0000, 0x0000 }, /* R124 */ | ||
1216 | { 0x0000, 0x0000, 0x0000 }, /* R125 */ | ||
1217 | { 0x0000, 0x0000, 0x0000 }, /* R126 */ | ||
1218 | { 0x0000, 0x0000, 0x0000 }, /* R127 */ | ||
1219 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R128 - GPIO Debounce */ | ||
1220 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R129 - GPIO Pin pull up Control */ | ||
1221 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R130 - GPIO Pull down Control */ | ||
1222 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R131 - GPIO Interrupt Mode */ | ||
1223 | { 0x0000, 0x0000, 0x0000 }, /* R132 */ | ||
1224 | { 0x00C0, 0x00C0, 0x0000 }, /* R133 - GPIO Control */ | ||
1225 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R134 - GPIO Configuration (i/o) */ | ||
1226 | { 0x1FFF, 0x1FFF, 0x0000 }, /* R135 - GPIO Pin Polarity / Type */ | ||
1227 | { 0x0000, 0x0000, 0x0000 }, /* R136 */ | ||
1228 | { 0x0000, 0x0000, 0x0000 }, /* R137 */ | ||
1229 | { 0x0000, 0x0000, 0x0000 }, /* R138 */ | ||
1230 | { 0x0000, 0x0000, 0x0000 }, /* R139 */ | ||
1231 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R140 - GPIO Function Select 1 */ | ||
1232 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R141 - GPIO Function Select 2 */ | ||
1233 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R142 - GPIO Function Select 3 */ | ||
1234 | { 0x000F, 0x000F, 0x0000 }, /* R143 - GPIO Function Select 4 */ | ||
1235 | { 0xF0FF, 0xF0FF, 0xA000 }, /* R144 - Digitiser Control (1) */ | ||
1236 | { 0x3707, 0x3707, 0x0000 }, /* R145 - Digitiser Control (2) */ | ||
1237 | { 0x0000, 0x0000, 0x0000 }, /* R146 */ | ||
1238 | { 0x0000, 0x0000, 0x0000 }, /* R147 */ | ||
1239 | { 0x0000, 0x0000, 0x0000 }, /* R148 */ | ||
1240 | { 0x0000, 0x0000, 0x0000 }, /* R149 */ | ||
1241 | { 0x0000, 0x0000, 0x0000 }, /* R150 */ | ||
1242 | { 0x0000, 0x0000, 0x0000 }, /* R151 */ | ||
1243 | { 0x7FFF, 0x7000, 0xFFFF }, /* R152 - AUX1 Readback */ | ||
1244 | { 0x7FFF, 0x7000, 0xFFFF }, /* R153 - AUX2 Readback */ | ||
1245 | { 0x7FFF, 0x7000, 0xFFFF }, /* R154 - AUX3 Readback */ | ||
1246 | { 0x7FFF, 0x7000, 0xFFFF }, /* R155 - AUX4 Readback */ | ||
1247 | { 0x0FFF, 0x0000, 0xFFFF }, /* R156 - USB Voltage Readback */ | ||
1248 | { 0x0FFF, 0x0000, 0xFFFF }, /* R157 - LINE Voltage Readback */ | ||
1249 | { 0x0FFF, 0x0000, 0xFFFF }, /* R158 - BATT Voltage Readback */ | ||
1250 | { 0x0FFF, 0x0000, 0xFFFF }, /* R159 - Chip Temp Readback */ | ||
1251 | { 0x0000, 0x0000, 0x0000 }, /* R160 */ | ||
1252 | { 0x0000, 0x0000, 0x0000 }, /* R161 */ | ||
1253 | { 0x0000, 0x0000, 0x0000 }, /* R162 */ | ||
1254 | { 0x000F, 0x000F, 0x0000 }, /* R163 - Generic Comparator Control */ | ||
1255 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R164 - Generic comparator 1 */ | ||
1256 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R165 - Generic comparator 2 */ | ||
1257 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R166 - Generic comparator 3 */ | ||
1258 | { 0xFFFF, 0xFFFF, 0x0000 }, /* R167 - Generic comparator 4 */ | ||
1259 | { 0xBFFF, 0xBFFF, 0x8000 }, /* R168 - Battery Charger Control 1 */ | ||
1260 | { 0xFFFF, 0x4FFF, 0xB000 }, /* R169 - Battery Charger Control 2 */ | ||
1261 | { 0x007F, 0x007F, 0x0000 }, /* R170 - Battery Charger Control 3 */ | ||
1262 | { 0x0000, 0x0000, 0x0000 }, /* R171 */ | ||
1263 | { 0x903F, 0x903F, 0xFFFF }, /* R172 - Current Sink Driver A */ | ||
1264 | { 0xE333, 0xE333, 0xFFFF }, /* R173 - CSA Flash control */ | ||
1265 | { 0x903F, 0x903F, 0xFFFF }, /* R174 - Current Sink Driver B */ | ||
1266 | { 0xE333, 0xE333, 0xFFFF }, /* R175 - CSB Flash control */ | ||
1267 | { 0x8F3F, 0x8F3F, 0xFFFF }, /* R176 - DCDC/LDO requested */ | ||
1268 | { 0x332D, 0x332D, 0x0000 }, /* R177 - DCDC Active options */ | ||
1269 | { 0x002D, 0x002D, 0x0000 }, /* R178 - DCDC Sleep options */ | ||
1270 | { 0x5177, 0x5177, 0x8000 }, /* R179 - Power-check comparator */ | ||
1271 | { 0x047F, 0x047F, 0x0000 }, /* R180 - DCDC1 Control */ | ||
1272 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R181 - DCDC1 Timeouts */ | ||
1273 | { 0x737F, 0x737F, 0x0000 }, /* R182 - DCDC1 Low Power */ | ||
1274 | { 0x535B, 0x535B, 0x0000 }, /* R183 - DCDC2 Control */ | ||
1275 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R184 - DCDC2 Timeouts */ | ||
1276 | { 0x0000, 0x0000, 0x0000 }, /* R185 */ | ||
1277 | { 0x047F, 0x047F, 0x0000 }, /* R186 - DCDC3 Control */ | ||
1278 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R187 - DCDC3 Timeouts */ | ||
1279 | { 0x737F, 0x737F, 0x0000 }, /* R188 - DCDC3 Low Power */ | ||
1280 | { 0x047F, 0x047F, 0x0000 }, /* R189 - DCDC4 Control */ | ||
1281 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R190 - DCDC4 Timeouts */ | ||
1282 | { 0x737F, 0x737F, 0x0000 }, /* R191 - DCDC4 Low Power */ | ||
1283 | { 0x535B, 0x535B, 0x0000 }, /* R192 - DCDC5 Control */ | ||
1284 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R193 - DCDC5 Timeouts */ | ||
1285 | { 0x0000, 0x0000, 0x0000 }, /* R194 */ | ||
1286 | { 0x047F, 0x047F, 0x0000 }, /* R195 - DCDC6 Control */ | ||
1287 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R196 - DCDC6 Timeouts */ | ||
1288 | { 0x737F, 0x737F, 0x0000 }, /* R197 - DCDC6 Low Power */ | ||
1289 | { 0x0000, 0x0000, 0x0000 }, /* R198 */ | ||
1290 | { 0xFFD3, 0xFFD3, 0x0000 }, /* R199 - Limit Switch Control */ | ||
1291 | { 0x441F, 0x441F, 0x0000 }, /* R200 - LDO1 Control */ | ||
1292 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R201 - LDO1 Timeouts */ | ||
1293 | { 0x331F, 0x331F, 0x0000 }, /* R202 - LDO1 Low Power */ | ||
1294 | { 0x441F, 0x441F, 0x0000 }, /* R203 - LDO2 Control */ | ||
1295 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R204 - LDO2 Timeouts */ | ||
1296 | { 0x331F, 0x331F, 0x0000 }, /* R205 - LDO2 Low Power */ | ||
1297 | { 0x441F, 0x441F, 0x0000 }, /* R206 - LDO3 Control */ | ||
1298 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R207 - LDO3 Timeouts */ | ||
1299 | { 0x331F, 0x331F, 0x0000 }, /* R208 - LDO3 Low Power */ | ||
1300 | { 0x441F, 0x441F, 0x0000 }, /* R209 - LDO4 Control */ | ||
1301 | { 0xFFC0, 0xFFC0, 0x0000 }, /* R210 - LDO4 Timeouts */ | ||
1302 | { 0x331F, 0x331F, 0x0000 }, /* R211 - LDO4 Low Power */ | ||
1303 | { 0x0000, 0x0000, 0x0000 }, /* R212 */ | ||
1304 | { 0x0000, 0x0000, 0x0000 }, /* R213 */ | ||
1305 | { 0x0000, 0x0000, 0x0000 }, /* R214 */ | ||
1306 | { 0x8F3F, 0x8F3F, 0x0000 }, /* R215 - VCC_FAULT Masks */ | ||
1307 | { 0xFF3F, 0xE03F, 0x0000 }, /* R216 - Main Bandgap Control */ | ||
1308 | { 0xEF2F, 0xE02F, 0x0000 }, /* R217 - OSC Control */ | ||
1309 | { 0xF3FF, 0xB3FF, 0xc000 }, /* R218 - RTC Tick Control */ | ||
1310 | { 0xFFFF, 0xFFFF, 0xFFFF }, /* R219 */ | ||
1311 | { 0x09FF, 0x01FF, 0x0000 }, /* R220 - RAM BIST 1 */ | ||
1312 | { 0x0000, 0x0000, 0x0000 }, /* R221 */ | ||
1313 | { 0xFFFF, 0xFFFF, 0xFFFF }, /* R222 */ | ||
1314 | { 0xFFFF, 0xFFFF, 0xFFFF }, /* R223 */ | ||
1315 | { 0x0000, 0x0000, 0x0000 }, /* R224 */ | ||
1316 | { 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */ | ||
1317 | { 0x0000, 0x0000, 0x0000 }, /* R226 */ | ||
1318 | { 0x0000, 0x0000, 0xFFFF }, /* R227 */ | ||
1319 | { 0x0000, 0x0000, 0x0000 }, /* R228 */ | ||
1320 | { 0x0000, 0x0000, 0x0000 }, /* R229 */ | ||
1321 | { 0xFFFF, 0x1FFF, 0xFFFF }, /* R230 - GPIO Pin Status */ | ||
1322 | { 0xFFFF, 0x1FFF, 0xFFFF }, /* R231 */ | ||
1323 | { 0xFFFF, 0x1FFF, 0xFFFF }, /* R232 */ | ||
1324 | { 0xFFFF, 0x1FFF, 0xFFFF }, /* R233 */ | ||
1325 | { 0x0000, 0x0000, 0x0000 }, /* R234 */ | ||
1326 | { 0x0000, 0x0000, 0x0000 }, /* R235 */ | ||
1327 | { 0x0000, 0x0000, 0x0000 }, /* R236 */ | ||
1328 | { 0x0000, 0x0000, 0x0000 }, /* R237 */ | ||
1329 | { 0x0000, 0x0000, 0x0000 }, /* R238 */ | ||
1330 | { 0x0000, 0x0000, 0x0000 }, /* R239 */ | ||
1331 | { 0x0000, 0x0000, 0x0000 }, /* R240 */ | ||
1332 | { 0x0000, 0x0000, 0x0000 }, /* R241 */ | ||
1333 | { 0x0000, 0x0000, 0x0000 }, /* R242 */ | ||
1334 | { 0x0000, 0x0000, 0x0000 }, /* R243 */ | ||
1335 | { 0x0000, 0x0000, 0x0000 }, /* R244 */ | ||
1336 | { 0x0000, 0x0000, 0x0000 }, /* R245 */ | ||
1337 | { 0x0000, 0x0000, 0x0000 }, /* R246 */ | ||
1338 | { 0x0000, 0x0000, 0x0000 }, /* R247 */ | ||
1339 | { 0xFFFF, 0x0010, 0xFFFF }, /* R248 */ | ||
1340 | { 0x0000, 0x0000, 0x0000 }, /* R249 */ | ||
1341 | { 0xFFFF, 0x0010, 0xFFFF }, /* R250 */ | ||
1342 | { 0xFFFF, 0x0010, 0xFFFF }, /* R251 */ | ||
1343 | { 0x0000, 0x0000, 0x0000 }, /* R252 */ | ||
1344 | { 0xFFFF, 0x0010, 0xFFFF }, /* R253 */ | ||
1345 | { 0x0000, 0x0000, 0x0000 }, /* R254 */ | ||
1346 | { 0x0000, 0x0000, 0x0000 }, /* R255 */ | ||
1347 | }; | ||
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c new file mode 100644 index 000000000000..6a0cedb5bb8a --- /dev/null +++ b/drivers/mfd/wm8400-core.c | |||
@@ -0,0 +1,455 @@ | |||
1 | /* | ||
2 | * Core driver for WM8400. | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation; either version 2 of the | ||
11 | * License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/bug.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/mfd/wm8400-private.h> | ||
19 | #include <linux/mfd/wm8400-audio.h> | ||
20 | |||
21 | static struct { | ||
22 | u16 readable; /* Mask of readable bits */ | ||
23 | u16 writable; /* Mask of writable bits */ | ||
24 | u16 vol; /* Mask of volatile bits */ | ||
25 | int is_codec; /* Register controlled by codec reset */ | ||
26 | u16 default_val; /* Value on reset */ | ||
27 | } reg_data[] = { | ||
28 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */ | ||
29 | { 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */ | ||
30 | { 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */ | ||
31 | { 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */ | ||
32 | { 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4 */ | ||
33 | { 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5 */ | ||
34 | { 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6 */ | ||
35 | { 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7 */ | ||
36 | { 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8 */ | ||
37 | { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9 */ | ||
38 | { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */ | ||
39 | { 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */ | ||
40 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */ | ||
41 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */ | ||
42 | { 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */ | ||
43 | { 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */ | ||
44 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */ | ||
45 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */ | ||
46 | { 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */ | ||
47 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */ | ||
48 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */ | ||
49 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */ | ||
50 | { 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */ | ||
51 | { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */ | ||
52 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */ | ||
53 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */ | ||
54 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */ | ||
55 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */ | ||
56 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */ | ||
57 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */ | ||
58 | { 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */ | ||
59 | { 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */ | ||
60 | { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */ | ||
61 | { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */ | ||
62 | { 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */ | ||
63 | { 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */ | ||
64 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */ | ||
65 | { 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */ | ||
66 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */ | ||
67 | { 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */ | ||
68 | { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */ | ||
69 | { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */ | ||
70 | { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */ | ||
71 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */ | ||
72 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */ | ||
73 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */ | ||
74 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */ | ||
75 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */ | ||
76 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */ | ||
77 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */ | ||
78 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */ | ||
79 | { 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */ | ||
80 | { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */ | ||
81 | { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */ | ||
82 | { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */ | ||
83 | { 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */ | ||
84 | { 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */ | ||
85 | { 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */ | ||
86 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */ | ||
87 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */ | ||
88 | { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */ | ||
89 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */ | ||
90 | { 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */ | ||
91 | { 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */ | ||
92 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */ | ||
93 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */ | ||
94 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */ | ||
95 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */ | ||
96 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */ | ||
97 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */ | ||
98 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */ | ||
99 | { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */ | ||
100 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */ | ||
101 | { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */ | ||
102 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */ | ||
103 | { 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */ | ||
104 | { 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */ | ||
105 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */ | ||
106 | { 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */ | ||
107 | { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */ | ||
108 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */ | ||
109 | { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */ | ||
110 | { 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */ | ||
111 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */ | ||
112 | { 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */ | ||
113 | }; | ||
114 | |||
115 | static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest) | ||
116 | { | ||
117 | int i, ret = 0; | ||
118 | |||
119 | BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); | ||
120 | |||
121 | /* If there are any volatile reads then read back the entire block */ | ||
122 | for (i = reg; i < reg + num_regs; i++) | ||
123 | if (reg_data[i].vol) { | ||
124 | ret = wm8400->read_dev(wm8400->io_data, reg, | ||
125 | num_regs, dest); | ||
126 | if (ret != 0) | ||
127 | return ret; | ||
128 | for (i = 0; i < num_regs; i++) | ||
129 | dest[i] = be16_to_cpu(dest[i]); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /* Otherwise use the cache */ | ||
135 | memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16)); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs, | ||
141 | u16 *src) | ||
142 | { | ||
143 | int ret, i; | ||
144 | |||
145 | BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); | ||
146 | |||
147 | for (i = 0; i < num_regs; i++) { | ||
148 | BUG_ON(!reg_data[reg + i].writable); | ||
149 | wm8400->reg_cache[reg + i] = src[i]; | ||
150 | src[i] = cpu_to_be16(src[i]); | ||
151 | } | ||
152 | |||
153 | /* Do the actual I/O */ | ||
154 | ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src); | ||
155 | if (ret != 0) | ||
156 | return -EIO; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * wm8400_reg_read - Single register read | ||
163 | * | ||
164 | * @wm8400: Pointer to wm8400 control structure | ||
165 | * @reg: Register to read | ||
166 | * | ||
167 | * @return Read value | ||
168 | */ | ||
169 | u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg) | ||
170 | { | ||
171 | u16 val; | ||
172 | |||
173 | mutex_lock(&wm8400->io_lock); | ||
174 | |||
175 | wm8400_read(wm8400, reg, 1, &val); | ||
176 | |||
177 | mutex_unlock(&wm8400->io_lock); | ||
178 | |||
179 | return val; | ||
180 | } | ||
181 | EXPORT_SYMBOL_GPL(wm8400_reg_read); | ||
182 | |||
183 | int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data) | ||
184 | { | ||
185 | int ret; | ||
186 | |||
187 | mutex_lock(&wm8400->io_lock); | ||
188 | |||
189 | ret = wm8400_read(wm8400, reg, count, data); | ||
190 | |||
191 | mutex_unlock(&wm8400->io_lock); | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(wm8400_block_read); | ||
196 | |||
197 | /** | ||
198 | * wm8400_set_bits - Bitmask write | ||
199 | * | ||
200 | * @wm8400: Pointer to wm8400 control structure | ||
201 | * @reg: Register to access | ||
202 | * @mask: Mask of bits to change | ||
203 | * @val: Value to set for masked bits | ||
204 | */ | ||
205 | int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val) | ||
206 | { | ||
207 | u16 tmp; | ||
208 | int ret; | ||
209 | |||
210 | mutex_lock(&wm8400->io_lock); | ||
211 | |||
212 | ret = wm8400_read(wm8400, reg, 1, &tmp); | ||
213 | tmp = (tmp & ~mask) | val; | ||
214 | if (ret == 0) | ||
215 | ret = wm8400_write(wm8400, reg, 1, &tmp); | ||
216 | |||
217 | mutex_unlock(&wm8400->io_lock); | ||
218 | |||
219 | return ret; | ||
220 | } | ||
221 | EXPORT_SYMBOL_GPL(wm8400_set_bits); | ||
222 | |||
223 | /** | ||
224 | * wm8400_reset_codec_reg_cache - Reset cached codec registers to | ||
225 | * their default values. | ||
226 | */ | ||
227 | void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400) | ||
228 | { | ||
229 | int i; | ||
230 | |||
231 | mutex_lock(&wm8400->io_lock); | ||
232 | |||
233 | /* Reset all codec registers to their initial value */ | ||
234 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) | ||
235 | if (reg_data[i].is_codec) | ||
236 | wm8400->reg_cache[i] = reg_data[i].default_val; | ||
237 | |||
238 | mutex_unlock(&wm8400->io_lock); | ||
239 | } | ||
240 | EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache); | ||
241 | |||
242 | /* | ||
243 | * wm8400_init - Generic initialisation | ||
244 | * | ||
245 | * The WM8400 can be configured as either an I2C or SPI device. Probe | ||
246 | * functions for each bus set up the accessors then call into this to | ||
247 | * set up the device itself. | ||
248 | */ | ||
249 | static int wm8400_init(struct wm8400 *wm8400, | ||
250 | struct wm8400_platform_data *pdata) | ||
251 | { | ||
252 | u16 reg; | ||
253 | int ret, i; | ||
254 | |||
255 | mutex_init(&wm8400->io_lock); | ||
256 | |||
257 | wm8400->dev->driver_data = wm8400; | ||
258 | |||
259 | /* Check that this is actually a WM8400 */ | ||
260 | ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, ®); | ||
261 | if (ret != 0) { | ||
262 | dev_err(wm8400->dev, "Chip ID register read failed\n"); | ||
263 | return -EIO; | ||
264 | } | ||
265 | if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) { | ||
266 | dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", | ||
267 | be16_to_cpu(reg)); | ||
268 | return -ENODEV; | ||
269 | } | ||
270 | |||
271 | /* We don't know what state the hardware is in and since this | ||
272 | * is a PMIC we can't reset it safely so initialise the register | ||
273 | * cache from the hardware. | ||
274 | */ | ||
275 | ret = wm8400->read_dev(wm8400->io_data, 0, | ||
276 | ARRAY_SIZE(wm8400->reg_cache), | ||
277 | wm8400->reg_cache); | ||
278 | if (ret != 0) { | ||
279 | dev_err(wm8400->dev, "Register cache read failed\n"); | ||
280 | return -EIO; | ||
281 | } | ||
282 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) | ||
283 | wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]); | ||
284 | |||
285 | /* If the codec is in reset use hard coded values */ | ||
286 | if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA)) | ||
287 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) | ||
288 | if (reg_data[i].is_codec) | ||
289 | wm8400->reg_cache[i] = reg_data[i].default_val; | ||
290 | |||
291 | ret = wm8400_read(wm8400, WM8400_ID, 1, ®); | ||
292 | if (ret != 0) { | ||
293 | dev_err(wm8400->dev, "ID register read failed: %d\n", ret); | ||
294 | return ret; | ||
295 | } | ||
296 | reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT; | ||
297 | dev_info(wm8400->dev, "WM8400 revision %x\n", reg); | ||
298 | |||
299 | if (pdata && pdata->platform_init) { | ||
300 | ret = pdata->platform_init(wm8400->dev); | ||
301 | if (ret != 0) | ||
302 | dev_err(wm8400->dev, "Platform init failed: %d\n", | ||
303 | ret); | ||
304 | } else | ||
305 | dev_warn(wm8400->dev, "No platform initialisation supplied\n"); | ||
306 | |||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | static void wm8400_release(struct wm8400 *wm8400) | ||
311 | { | ||
312 | int i; | ||
313 | |||
314 | for (i = 0; i < ARRAY_SIZE(wm8400->regulators); i++) | ||
315 | if (wm8400->regulators[i].name) | ||
316 | platform_device_unregister(&wm8400->regulators[i]); | ||
317 | } | ||
318 | |||
319 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
320 | static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest) | ||
321 | { | ||
322 | struct i2c_client *i2c = io_data; | ||
323 | struct i2c_msg xfer[2]; | ||
324 | int ret; | ||
325 | |||
326 | /* Write register */ | ||
327 | xfer[0].addr = i2c->addr; | ||
328 | xfer[0].flags = 0; | ||
329 | xfer[0].len = 1; | ||
330 | xfer[0].buf = ® | ||
331 | |||
332 | /* Read data */ | ||
333 | xfer[1].addr = i2c->addr; | ||
334 | xfer[1].flags = I2C_M_RD; | ||
335 | xfer[1].len = count * sizeof(u16); | ||
336 | xfer[1].buf = (u8 *)dest; | ||
337 | |||
338 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
339 | if (ret == 2) | ||
340 | ret = 0; | ||
341 | else if (ret >= 0) | ||
342 | ret = -EIO; | ||
343 | |||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src) | ||
348 | { | ||
349 | struct i2c_client *i2c = io_data; | ||
350 | u8 *msg; | ||
351 | int ret; | ||
352 | |||
353 | /* We add 1 byte for device register - ideally I2C would gather. */ | ||
354 | msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL); | ||
355 | if (msg == NULL) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | msg[0] = reg; | ||
359 | memcpy(&msg[1], src, count * sizeof(u16)); | ||
360 | |||
361 | ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1); | ||
362 | |||
363 | if (ret == (count * 2) + 1) | ||
364 | ret = 0; | ||
365 | else if (ret >= 0) | ||
366 | ret = -EIO; | ||
367 | |||
368 | kfree(msg); | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | static int wm8400_i2c_probe(struct i2c_client *i2c, | ||
374 | const struct i2c_device_id *id) | ||
375 | { | ||
376 | struct wm8400 *wm8400; | ||
377 | int ret; | ||
378 | |||
379 | wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL); | ||
380 | if (wm8400 == NULL) { | ||
381 | ret = -ENOMEM; | ||
382 | goto err; | ||
383 | } | ||
384 | |||
385 | wm8400->io_data = i2c; | ||
386 | wm8400->read_dev = wm8400_i2c_read; | ||
387 | wm8400->write_dev = wm8400_i2c_write; | ||
388 | wm8400->dev = &i2c->dev; | ||
389 | i2c_set_clientdata(i2c, wm8400); | ||
390 | |||
391 | ret = wm8400_init(wm8400, i2c->dev.platform_data); | ||
392 | if (ret != 0) | ||
393 | goto struct_err; | ||
394 | |||
395 | return 0; | ||
396 | |||
397 | struct_err: | ||
398 | i2c_set_clientdata(i2c, NULL); | ||
399 | kfree(wm8400); | ||
400 | err: | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int wm8400_i2c_remove(struct i2c_client *i2c) | ||
405 | { | ||
406 | struct wm8400 *wm8400 = i2c_get_clientdata(i2c); | ||
407 | |||
408 | wm8400_release(wm8400); | ||
409 | i2c_set_clientdata(i2c, NULL); | ||
410 | kfree(wm8400); | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static const struct i2c_device_id wm8400_i2c_id[] = { | ||
416 | { "wm8400", 0 }, | ||
417 | { } | ||
418 | }; | ||
419 | MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id); | ||
420 | |||
421 | static struct i2c_driver wm8400_i2c_driver = { | ||
422 | .driver = { | ||
423 | .name = "WM8400", | ||
424 | .owner = THIS_MODULE, | ||
425 | }, | ||
426 | .probe = wm8400_i2c_probe, | ||
427 | .remove = wm8400_i2c_remove, | ||
428 | .id_table = wm8400_i2c_id, | ||
429 | }; | ||
430 | #endif | ||
431 | |||
432 | static int __init wm8400_module_init(void) | ||
433 | { | ||
434 | int ret = -ENODEV; | ||
435 | |||
436 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
437 | ret = i2c_add_driver(&wm8400_i2c_driver); | ||
438 | if (ret != 0) | ||
439 | pr_err("Failed to register I2C driver: %d\n", ret); | ||
440 | #endif | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | module_init(wm8400_module_init); | ||
445 | |||
446 | static void __exit wm8400_module_exit(void) | ||
447 | { | ||
448 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
449 | i2c_del_driver(&wm8400_i2c_driver); | ||
450 | #endif | ||
451 | } | ||
452 | module_exit(wm8400_module_exit); | ||
453 | |||
454 | MODULE_LICENSE("GPL"); | ||
455 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||