Commit b8380c1a661f1f853418ff2eb798f27a11cade57
Committed by
Samuel Ortiz
1 parent
44faac3155
Exists in
master
and in
7 other branches
mfd: Register WM8400 codec device
Register a child device for the codec in the WM8400. Also switch the unregistration of the MFD devices to use the MFD core since the current code is hand rolling the same thing. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@openedhand.com>
Showing 2 changed files with 26 additions and 6 deletions Inline Diff
drivers/mfd/Kconfig
1 | # | 1 | # |
2 | # Multifunction miscellaneous devices | 2 | # Multifunction miscellaneous devices |
3 | # | 3 | # |
4 | 4 | ||
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 | 8 | config MFD_CORE |
9 | tristate | 9 | tristate |
10 | default n | 10 | default n |
11 | 11 | ||
12 | config MFD_SM501 | 12 | config MFD_SM501 |
13 | tristate "Support for Silicon Motion SM501" | 13 | tristate "Support for Silicon Motion SM501" |
14 | ---help--- | 14 | ---help--- |
15 | This is the core driver for the Silicon Motion SM501 multimedia | 15 | This is the core driver for the Silicon Motion SM501 multimedia |
16 | companion chip. This device is a multifunction device which may | 16 | companion chip. This device is a multifunction device which may |
17 | provide numerous interfaces including USB host controller, USB gadget, | 17 | provide numerous interfaces including USB host controller, USB gadget, |
18 | asynchronous serial ports, audio functions, and a dual display video | 18 | asynchronous serial ports, audio functions, and a dual display video |
19 | 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 |
20 | varying functions enabled. | 20 | varying functions enabled. |
21 | 21 | ||
22 | config MFD_SM501_GPIO | 22 | config MFD_SM501_GPIO |
23 | bool "Export GPIO via GPIO layer" | 23 | bool "Export GPIO via GPIO layer" |
24 | depends on MFD_SM501 && GPIOLIB | 24 | depends on MFD_SM501 && GPIOLIB |
25 | ---help--- | 25 | ---help--- |
26 | This option uses the gpio library layer to export the 64 GPIO | 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 | 27 | lines on the SM501. The platform data is used to supply the |
28 | base number for the first GPIO line to register. | 28 | base number for the first GPIO line to register. |
29 | 29 | ||
30 | config MFD_ASIC3 | 30 | config MFD_ASIC3 |
31 | bool "Support for Compaq ASIC3" | 31 | bool "Support for Compaq ASIC3" |
32 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 32 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM |
33 | ---help--- | 33 | ---help--- |
34 | This driver supports the ASIC3 multifunction chip found on many | 34 | This driver supports the ASIC3 multifunction chip found on many |
35 | PDAs (mainly iPAQ and HTC based ones) | 35 | PDAs (mainly iPAQ and HTC based ones) |
36 | 36 | ||
37 | config HTC_EGPIO | 37 | config HTC_EGPIO |
38 | bool "HTC EGPIO support" | 38 | bool "HTC EGPIO support" |
39 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 39 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM |
40 | help | 40 | help |
41 | This driver supports the CPLD egpio chip present on | 41 | This driver supports the CPLD egpio chip present on |
42 | several HTC phones. It provides basic support for input | 42 | several HTC phones. It provides basic support for input |
43 | pins, output pins, and irqs. | 43 | pins, output pins, and irqs. |
44 | 44 | ||
45 | config HTC_PASIC3 | 45 | config HTC_PASIC3 |
46 | tristate "HTC PASIC3 LED/DS1WM chip support" | 46 | tristate "HTC PASIC3 LED/DS1WM chip support" |
47 | help | 47 | help |
48 | This core driver provides register access for the LED/DS1WM | 48 | This core driver provides register access for the LED/DS1WM |
49 | chips labeled "AIC2" and "AIC3", found on HTC Blueangel and | 49 | chips labeled "AIC2" and "AIC3", found on HTC Blueangel and |
50 | HTC Magician devices, respectively. Actual functionality is | 50 | HTC Magician devices, respectively. Actual functionality is |
51 | handled by the leds-pasic3 and ds1wm drivers. | 51 | handled by the leds-pasic3 and ds1wm drivers. |
52 | 52 | ||
53 | config UCB1400_CORE | 53 | config UCB1400_CORE |
54 | tristate "Philips UCB1400 Core driver" | 54 | tristate "Philips UCB1400 Core driver" |
55 | depends on AC97_BUS | 55 | depends on AC97_BUS |
56 | depends on GPIOLIB | 56 | depends on GPIOLIB |
57 | help | 57 | help |
58 | This enables support for the Philips UCB1400 core functions. | 58 | This enables support for the Philips UCB1400 core functions. |
59 | The UCB1400 is an AC97 audio codec. | 59 | The UCB1400 is an AC97 audio codec. |
60 | 60 | ||
61 | To compile this driver as a module, choose M here: the | 61 | To compile this driver as a module, choose M here: the |
62 | module will be called ucb1400_core. | 62 | module will be called ucb1400_core. |
63 | 63 | ||
64 | config TWL4030_CORE | 64 | config TWL4030_CORE |
65 | bool "Texas Instruments TWL4030/TPS659x0 Support" | 65 | bool "Texas Instruments TWL4030/TPS659x0 Support" |
66 | depends on I2C=y && GENERIC_HARDIRQS | 66 | depends on I2C=y && GENERIC_HARDIRQS |
67 | help | 67 | help |
68 | Say yes here if you have TWL4030 family chip on your board. | 68 | Say yes here if you have TWL4030 family chip on your board. |
69 | This core driver provides register access and IRQ handling | 69 | This core driver provides register access and IRQ handling |
70 | facilities, and registers devices for the various functions | 70 | facilities, and registers devices for the various functions |
71 | so that function-specific drivers can bind to them. | 71 | so that function-specific drivers can bind to them. |
72 | 72 | ||
73 | These multi-function chips are found on many OMAP2 and OMAP3 | 73 | These multi-function chips are found on many OMAP2 and OMAP3 |
74 | boards, providing power management, RTC, GPIO, keypad, a | 74 | boards, providing power management, RTC, GPIO, keypad, a |
75 | high speed USB OTG transceiver, an audio codec (on most | 75 | high speed USB OTG transceiver, an audio codec (on most |
76 | versions) and many other features. | 76 | versions) and many other features. |
77 | 77 | ||
78 | config MFD_TMIO | 78 | config MFD_TMIO |
79 | bool | 79 | bool |
80 | default n | 80 | default n |
81 | 81 | ||
82 | config MFD_T7L66XB | 82 | config MFD_T7L66XB |
83 | bool "Support Toshiba T7L66XB" | 83 | bool "Support Toshiba T7L66XB" |
84 | depends on ARM && HAVE_CLK | 84 | depends on ARM && HAVE_CLK |
85 | select MFD_CORE | 85 | select MFD_CORE |
86 | select MFD_TMIO | 86 | select MFD_TMIO |
87 | help | 87 | help |
88 | Support for Toshiba Mobile IO Controller T7L66XB | 88 | Support for Toshiba Mobile IO Controller T7L66XB |
89 | 89 | ||
90 | config MFD_TC6387XB | 90 | config MFD_TC6387XB |
91 | bool "Support Toshiba TC6387XB" | 91 | bool "Support Toshiba TC6387XB" |
92 | depends on ARM && HAVE_CLK | 92 | depends on ARM && HAVE_CLK |
93 | select MFD_CORE | 93 | select MFD_CORE |
94 | select MFD_TMIO | 94 | select MFD_TMIO |
95 | help | 95 | help |
96 | Support for Toshiba Mobile IO Controller TC6387XB | 96 | Support for Toshiba Mobile IO Controller TC6387XB |
97 | 97 | ||
98 | config MFD_TC6393XB | 98 | config MFD_TC6393XB |
99 | bool "Support Toshiba TC6393XB" | 99 | bool "Support Toshiba TC6393XB" |
100 | depends on GPIOLIB && ARM | 100 | depends on GPIOLIB && ARM |
101 | select MFD_CORE | 101 | select MFD_CORE |
102 | select MFD_TMIO | 102 | select MFD_TMIO |
103 | help | 103 | help |
104 | Support for Toshiba Mobile IO Controller TC6393XB | 104 | Support for Toshiba Mobile IO Controller TC6393XB |
105 | 105 | ||
106 | config PMIC_DA903X | 106 | config PMIC_DA903X |
107 | bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" | 107 | bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" |
108 | depends on I2C=y | 108 | depends on I2C=y |
109 | help | 109 | help |
110 | Say yes here to support for Dialog Semiconductor DA9030 (a.k.a | 110 | Say yes here to support for Dialog Semiconductor DA9030 (a.k.a |
111 | ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC | 111 | ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC |
112 | usually found on PXA processors-based platforms. This includes | 112 | usually found on PXA processors-based platforms. This includes |
113 | the I2C driver and the core APIs _only_, you have to select | 113 | the I2C driver and the core APIs _only_, you have to select |
114 | individual components like LCD backlight, voltage regulators, | 114 | individual components like LCD backlight, voltage regulators, |
115 | LEDs and battery-charger under the corresponding menus. | 115 | LEDs and battery-charger under the corresponding menus. |
116 | 116 | ||
117 | config MFD_WM8400 | 117 | config MFD_WM8400 |
118 | tristate "Support Wolfson Microelectronics WM8400" | 118 | tristate "Support Wolfson Microelectronics WM8400" |
119 | select MFD_CORE | ||
119 | depends on I2C | 120 | depends on I2C |
120 | help | 121 | help |
121 | Support for the Wolfson Microelecronics WM8400 PMIC and audio | 122 | Support for the Wolfson Microelecronics WM8400 PMIC and audio |
122 | CODEC. This driver adds provides common support for accessing | 123 | CODEC. This driver adds provides common support for accessing |
123 | the device, additional drivers must be enabled in order to use | 124 | the device, additional drivers must be enabled in order to use |
124 | the functionality of the device. | 125 | the functionality of the device. |
125 | 126 | ||
126 | config MFD_WM8350 | 127 | config MFD_WM8350 |
127 | tristate | 128 | tristate |
128 | 129 | ||
129 | config MFD_WM8350_CONFIG_MODE_0 | 130 | config MFD_WM8350_CONFIG_MODE_0 |
130 | bool | 131 | bool |
131 | depends on MFD_WM8350 | 132 | depends on MFD_WM8350 |
132 | 133 | ||
133 | config MFD_WM8350_CONFIG_MODE_1 | 134 | config MFD_WM8350_CONFIG_MODE_1 |
134 | bool | 135 | bool |
135 | depends on MFD_WM8350 | 136 | depends on MFD_WM8350 |
136 | 137 | ||
137 | config MFD_WM8350_CONFIG_MODE_2 | 138 | config MFD_WM8350_CONFIG_MODE_2 |
138 | bool | 139 | bool |
139 | depends on MFD_WM8350 | 140 | depends on MFD_WM8350 |
140 | 141 | ||
141 | config MFD_WM8350_CONFIG_MODE_3 | 142 | config MFD_WM8350_CONFIG_MODE_3 |
142 | bool | 143 | bool |
143 | depends on MFD_WM8350 | 144 | depends on MFD_WM8350 |
144 | 145 | ||
145 | config MFD_WM8350_I2C | 146 | config MFD_WM8350_I2C |
146 | tristate "Support Wolfson Microelectronics WM8350 with I2C" | 147 | tristate "Support Wolfson Microelectronics WM8350 with I2C" |
147 | select MFD_WM8350 | 148 | select MFD_WM8350 |
148 | depends on I2C | 149 | depends on I2C |
149 | help | 150 | help |
150 | The WM8350 is an integrated audio and power management | 151 | The WM8350 is an integrated audio and power management |
151 | subsystem with watchdog and RTC functionality for embedded | 152 | subsystem with watchdog and RTC functionality for embedded |
152 | systems. This option enables core support for the WM8350 with | 153 | systems. This option enables core support for the WM8350 with |
153 | I2C as the control interface. Additional options must be | 154 | I2C as the control interface. Additional options must be |
154 | selected to enable support for the functionality of the chip. | 155 | selected to enable support for the functionality of the chip. |
155 | 156 | ||
156 | endmenu | 157 | endmenu |
157 | 158 | ||
158 | menu "Multimedia Capabilities Port drivers" | 159 | menu "Multimedia Capabilities Port drivers" |
159 | depends on ARCH_SA1100 | 160 | depends on ARCH_SA1100 |
160 | 161 | ||
161 | config MCP | 162 | config MCP |
162 | tristate | 163 | tristate |
163 | 164 | ||
164 | # Interface drivers | 165 | # Interface drivers |
165 | config MCP_SA11X0 | 166 | config MCP_SA11X0 |
166 | tristate "Support SA11x0 MCP interface" | 167 | tristate "Support SA11x0 MCP interface" |
167 | depends on ARCH_SA1100 | 168 | depends on ARCH_SA1100 |
168 | select MCP | 169 | select MCP |
169 | 170 | ||
170 | # Chip drivers | 171 | # Chip drivers |
171 | config MCP_UCB1200 | 172 | config MCP_UCB1200 |
172 | tristate "Support for UCB1200 / UCB1300" | 173 | tristate "Support for UCB1200 / UCB1300" |
173 | depends on MCP | 174 | depends on MCP |
174 | 175 | ||
175 | config MCP_UCB1200_TS | 176 | config MCP_UCB1200_TS |
176 | tristate "Touchscreen interface support" | 177 | tristate "Touchscreen interface support" |
177 | depends on MCP_UCB1200 && INPUT | 178 | depends on MCP_UCB1200 && INPUT |
178 | 179 | ||
179 | endmenu | 180 | endmenu |
180 | 181 |
drivers/mfd/wm8400-core.c
1 | /* | 1 | /* |
2 | * Core driver for WM8400. | 2 | * Core driver for WM8400. |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics PLC. | 4 | * Copyright 2008 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 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 | 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 | 10 | * published by the Free Software Foundation; either version 2 of the |
11 | * License, or (at your option) any later version. | 11 | * License, or (at your option) any later version. |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/bug.h> | 15 | #include <linux/bug.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/mfd/core.h> | ||
18 | #include <linux/mfd/wm8400-private.h> | 19 | #include <linux/mfd/wm8400-private.h> |
19 | #include <linux/mfd/wm8400-audio.h> | 20 | #include <linux/mfd/wm8400-audio.h> |
20 | 21 | ||
21 | static struct { | 22 | static struct { |
22 | u16 readable; /* Mask of readable bits */ | 23 | u16 readable; /* Mask of readable bits */ |
23 | u16 writable; /* Mask of writable bits */ | 24 | u16 writable; /* Mask of writable bits */ |
24 | u16 vol; /* Mask of volatile bits */ | 25 | u16 vol; /* Mask of volatile bits */ |
25 | int is_codec; /* Register controlled by codec reset */ | 26 | int is_codec; /* Register controlled by codec reset */ |
26 | u16 default_val; /* Value on reset */ | 27 | u16 default_val; /* Value on reset */ |
27 | } reg_data[] = { | 28 | } reg_data[] = { |
28 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */ | 29 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */ |
29 | { 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */ | 30 | { 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */ |
30 | { 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */ | 31 | { 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */ |
31 | { 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */ | 32 | { 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */ |
32 | { 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4 */ | 33 | { 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4 */ |
33 | { 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5 */ | 34 | { 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5 */ |
34 | { 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6 */ | 35 | { 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6 */ |
35 | { 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7 */ | 36 | { 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7 */ |
36 | { 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8 */ | 37 | { 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8 */ |
37 | { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9 */ | 38 | { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9 */ |
38 | { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */ | 39 | { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */ |
39 | { 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */ | 40 | { 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */ |
40 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */ | 41 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */ |
41 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */ | 42 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */ |
42 | { 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */ | 43 | { 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */ |
43 | { 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */ | 44 | { 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */ |
44 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */ | 45 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */ |
45 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */ | 46 | { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */ |
46 | { 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */ | 47 | { 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */ |
47 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */ | 48 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */ |
48 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */ | 49 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */ |
49 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */ | 50 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */ |
50 | { 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */ | 51 | { 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */ |
51 | { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */ | 52 | { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */ |
52 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */ | 53 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */ |
53 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */ | 54 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */ |
54 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */ | 55 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */ |
55 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */ | 56 | { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */ |
56 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */ | 57 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */ |
57 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */ | 58 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */ |
58 | { 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */ | 59 | { 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */ |
59 | { 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */ | 60 | { 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */ |
60 | { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */ | 61 | { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */ |
61 | { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */ | 62 | { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */ |
62 | { 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */ | 63 | { 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */ |
63 | { 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */ | 64 | { 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */ |
64 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */ | 65 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */ |
65 | { 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */ | 66 | { 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */ |
66 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */ | 67 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */ |
67 | { 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */ | 68 | { 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */ |
68 | { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */ | 69 | { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */ |
69 | { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */ | 70 | { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */ |
70 | { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */ | 71 | { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */ |
71 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */ | 72 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */ |
72 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */ | 73 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */ |
73 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */ | 74 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */ |
74 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */ | 75 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */ |
75 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */ | 76 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */ |
76 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */ | 77 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */ |
77 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */ | 78 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */ |
78 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */ | 79 | { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */ |
79 | { 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */ | 80 | { 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */ |
80 | { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */ | 81 | { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */ |
81 | { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */ | 82 | { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */ |
82 | { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */ | 83 | { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */ |
83 | { 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */ | 84 | { 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */ |
84 | { 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */ | 85 | { 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */ |
85 | { 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */ | 86 | { 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */ |
86 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */ | 87 | { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */ |
87 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */ | 88 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */ |
88 | { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */ | 89 | { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */ |
89 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */ | 90 | { 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */ |
90 | { 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */ | 91 | { 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */ |
91 | { 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */ | 92 | { 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */ |
92 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */ | 93 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */ |
93 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */ | 94 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */ |
94 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */ | 95 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */ |
95 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */ | 96 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */ |
96 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */ | 97 | { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */ |
97 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */ | 98 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */ |
98 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */ | 99 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */ |
99 | { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */ | 100 | { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */ |
100 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */ | 101 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */ |
101 | { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */ | 102 | { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */ |
102 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */ | 103 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */ |
103 | { 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */ | 104 | { 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */ |
104 | { 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */ | 105 | { 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */ |
105 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */ | 106 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */ |
106 | { 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */ | 107 | { 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */ |
107 | { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */ | 108 | { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */ |
108 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */ | 109 | { 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */ |
109 | { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */ | 110 | { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */ |
110 | { 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */ | 111 | { 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */ |
111 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */ | 112 | { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */ |
112 | { 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */ | 113 | { 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */ |
113 | }; | 114 | }; |
114 | 115 | ||
115 | static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest) | 116 | static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest) |
116 | { | 117 | { |
117 | int i, ret = 0; | 118 | int i, ret = 0; |
118 | 119 | ||
119 | BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); | 120 | BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); |
120 | 121 | ||
121 | /* If there are any volatile reads then read back the entire block */ | 122 | /* If there are any volatile reads then read back the entire block */ |
122 | for (i = reg; i < reg + num_regs; i++) | 123 | for (i = reg; i < reg + num_regs; i++) |
123 | if (reg_data[i].vol) { | 124 | if (reg_data[i].vol) { |
124 | ret = wm8400->read_dev(wm8400->io_data, reg, | 125 | ret = wm8400->read_dev(wm8400->io_data, reg, |
125 | num_regs, dest); | 126 | num_regs, dest); |
126 | if (ret != 0) | 127 | if (ret != 0) |
127 | return ret; | 128 | return ret; |
128 | for (i = 0; i < num_regs; i++) | 129 | for (i = 0; i < num_regs; i++) |
129 | dest[i] = be16_to_cpu(dest[i]); | 130 | dest[i] = be16_to_cpu(dest[i]); |
130 | 131 | ||
131 | return 0; | 132 | return 0; |
132 | } | 133 | } |
133 | 134 | ||
134 | /* Otherwise use the cache */ | 135 | /* Otherwise use the cache */ |
135 | memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16)); | 136 | memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16)); |
136 | 137 | ||
137 | return 0; | 138 | return 0; |
138 | } | 139 | } |
139 | 140 | ||
140 | static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs, | 141 | static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs, |
141 | u16 *src) | 142 | u16 *src) |
142 | { | 143 | { |
143 | int ret, i; | 144 | int ret, i; |
144 | 145 | ||
145 | BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); | 146 | BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); |
146 | 147 | ||
147 | for (i = 0; i < num_regs; i++) { | 148 | for (i = 0; i < num_regs; i++) { |
148 | BUG_ON(!reg_data[reg + i].writable); | 149 | BUG_ON(!reg_data[reg + i].writable); |
149 | wm8400->reg_cache[reg + i] = src[i]; | 150 | wm8400->reg_cache[reg + i] = src[i]; |
150 | src[i] = cpu_to_be16(src[i]); | 151 | src[i] = cpu_to_be16(src[i]); |
151 | } | 152 | } |
152 | 153 | ||
153 | /* Do the actual I/O */ | 154 | /* Do the actual I/O */ |
154 | ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src); | 155 | ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src); |
155 | if (ret != 0) | 156 | if (ret != 0) |
156 | return -EIO; | 157 | return -EIO; |
157 | 158 | ||
158 | return 0; | 159 | return 0; |
159 | } | 160 | } |
160 | 161 | ||
161 | /** | 162 | /** |
162 | * wm8400_reg_read - Single register read | 163 | * wm8400_reg_read - Single register read |
163 | * | 164 | * |
164 | * @wm8400: Pointer to wm8400 control structure | 165 | * @wm8400: Pointer to wm8400 control structure |
165 | * @reg: Register to read | 166 | * @reg: Register to read |
166 | * | 167 | * |
167 | * @return Read value | 168 | * @return Read value |
168 | */ | 169 | */ |
169 | u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg) | 170 | u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg) |
170 | { | 171 | { |
171 | u16 val; | 172 | u16 val; |
172 | 173 | ||
173 | mutex_lock(&wm8400->io_lock); | 174 | mutex_lock(&wm8400->io_lock); |
174 | 175 | ||
175 | wm8400_read(wm8400, reg, 1, &val); | 176 | wm8400_read(wm8400, reg, 1, &val); |
176 | 177 | ||
177 | mutex_unlock(&wm8400->io_lock); | 178 | mutex_unlock(&wm8400->io_lock); |
178 | 179 | ||
179 | return val; | 180 | return val; |
180 | } | 181 | } |
181 | EXPORT_SYMBOL_GPL(wm8400_reg_read); | 182 | EXPORT_SYMBOL_GPL(wm8400_reg_read); |
182 | 183 | ||
183 | int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data) | 184 | int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data) |
184 | { | 185 | { |
185 | int ret; | 186 | int ret; |
186 | 187 | ||
187 | mutex_lock(&wm8400->io_lock); | 188 | mutex_lock(&wm8400->io_lock); |
188 | 189 | ||
189 | ret = wm8400_read(wm8400, reg, count, data); | 190 | ret = wm8400_read(wm8400, reg, count, data); |
190 | 191 | ||
191 | mutex_unlock(&wm8400->io_lock); | 192 | mutex_unlock(&wm8400->io_lock); |
192 | 193 | ||
193 | return ret; | 194 | return ret; |
194 | } | 195 | } |
195 | EXPORT_SYMBOL_GPL(wm8400_block_read); | 196 | EXPORT_SYMBOL_GPL(wm8400_block_read); |
196 | 197 | ||
197 | /** | 198 | /** |
198 | * wm8400_set_bits - Bitmask write | 199 | * wm8400_set_bits - Bitmask write |
199 | * | 200 | * |
200 | * @wm8400: Pointer to wm8400 control structure | 201 | * @wm8400: Pointer to wm8400 control structure |
201 | * @reg: Register to access | 202 | * @reg: Register to access |
202 | * @mask: Mask of bits to change | 203 | * @mask: Mask of bits to change |
203 | * @val: Value to set for masked bits | 204 | * @val: Value to set for masked bits |
204 | */ | 205 | */ |
205 | int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val) | 206 | int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val) |
206 | { | 207 | { |
207 | u16 tmp; | 208 | u16 tmp; |
208 | int ret; | 209 | int ret; |
209 | 210 | ||
210 | mutex_lock(&wm8400->io_lock); | 211 | mutex_lock(&wm8400->io_lock); |
211 | 212 | ||
212 | ret = wm8400_read(wm8400, reg, 1, &tmp); | 213 | ret = wm8400_read(wm8400, reg, 1, &tmp); |
213 | tmp = (tmp & ~mask) | val; | 214 | tmp = (tmp & ~mask) | val; |
214 | if (ret == 0) | 215 | if (ret == 0) |
215 | ret = wm8400_write(wm8400, reg, 1, &tmp); | 216 | ret = wm8400_write(wm8400, reg, 1, &tmp); |
216 | 217 | ||
217 | mutex_unlock(&wm8400->io_lock); | 218 | mutex_unlock(&wm8400->io_lock); |
218 | 219 | ||
219 | return ret; | 220 | return ret; |
220 | } | 221 | } |
221 | EXPORT_SYMBOL_GPL(wm8400_set_bits); | 222 | EXPORT_SYMBOL_GPL(wm8400_set_bits); |
222 | 223 | ||
223 | /** | 224 | /** |
224 | * wm8400_reset_codec_reg_cache - Reset cached codec registers to | 225 | * wm8400_reset_codec_reg_cache - Reset cached codec registers to |
225 | * their default values. | 226 | * their default values. |
226 | */ | 227 | */ |
227 | void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400) | 228 | void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400) |
228 | { | 229 | { |
229 | int i; | 230 | int i; |
230 | 231 | ||
231 | mutex_lock(&wm8400->io_lock); | 232 | mutex_lock(&wm8400->io_lock); |
232 | 233 | ||
233 | /* Reset all codec registers to their initial value */ | 234 | /* Reset all codec registers to their initial value */ |
234 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) | 235 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) |
235 | if (reg_data[i].is_codec) | 236 | if (reg_data[i].is_codec) |
236 | wm8400->reg_cache[i] = reg_data[i].default_val; | 237 | wm8400->reg_cache[i] = reg_data[i].default_val; |
237 | 238 | ||
238 | mutex_unlock(&wm8400->io_lock); | 239 | mutex_unlock(&wm8400->io_lock); |
239 | } | 240 | } |
240 | EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache); | 241 | EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache); |
241 | 242 | ||
243 | static int wm8400_register_codec(struct wm8400 *wm8400) | ||
244 | { | ||
245 | struct mfd_cell cell = { | ||
246 | .name = "wm8400-codec", | ||
247 | .driver_data = wm8400, | ||
248 | }; | ||
249 | |||
250 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); | ||
251 | } | ||
252 | |||
242 | /* | 253 | /* |
243 | * wm8400_init - Generic initialisation | 254 | * wm8400_init - Generic initialisation |
244 | * | 255 | * |
245 | * The WM8400 can be configured as either an I2C or SPI device. Probe | 256 | * 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 | 257 | * functions for each bus set up the accessors then call into this to |
247 | * set up the device itself. | 258 | * set up the device itself. |
248 | */ | 259 | */ |
249 | static int wm8400_init(struct wm8400 *wm8400, | 260 | static int wm8400_init(struct wm8400 *wm8400, |
250 | struct wm8400_platform_data *pdata) | 261 | struct wm8400_platform_data *pdata) |
251 | { | 262 | { |
252 | u16 reg; | 263 | u16 reg; |
253 | int ret, i; | 264 | int ret, i; |
254 | 265 | ||
255 | mutex_init(&wm8400->io_lock); | 266 | mutex_init(&wm8400->io_lock); |
256 | 267 | ||
257 | wm8400->dev->driver_data = wm8400; | 268 | wm8400->dev->driver_data = wm8400; |
258 | 269 | ||
259 | /* Check that this is actually a WM8400 */ | 270 | /* Check that this is actually a WM8400 */ |
260 | ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, ®); | 271 | ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, ®); |
261 | if (ret != 0) { | 272 | if (ret != 0) { |
262 | dev_err(wm8400->dev, "Chip ID register read failed\n"); | 273 | dev_err(wm8400->dev, "Chip ID register read failed\n"); |
263 | return -EIO; | 274 | return -EIO; |
264 | } | 275 | } |
265 | if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) { | 276 | 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", | 277 | dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", |
267 | be16_to_cpu(reg)); | 278 | be16_to_cpu(reg)); |
268 | return -ENODEV; | 279 | return -ENODEV; |
269 | } | 280 | } |
270 | 281 | ||
271 | /* We don't know what state the hardware is in and since this | 282 | /* 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 | 283 | * is a PMIC we can't reset it safely so initialise the register |
273 | * cache from the hardware. | 284 | * cache from the hardware. |
274 | */ | 285 | */ |
275 | ret = wm8400->read_dev(wm8400->io_data, 0, | 286 | ret = wm8400->read_dev(wm8400->io_data, 0, |
276 | ARRAY_SIZE(wm8400->reg_cache), | 287 | ARRAY_SIZE(wm8400->reg_cache), |
277 | wm8400->reg_cache); | 288 | wm8400->reg_cache); |
278 | if (ret != 0) { | 289 | if (ret != 0) { |
279 | dev_err(wm8400->dev, "Register cache read failed\n"); | 290 | dev_err(wm8400->dev, "Register cache read failed\n"); |
280 | return -EIO; | 291 | return -EIO; |
281 | } | 292 | } |
282 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) | 293 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) |
283 | wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]); | 294 | wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]); |
284 | 295 | ||
285 | /* If the codec is in reset use hard coded values */ | 296 | /* If the codec is in reset use hard coded values */ |
286 | if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA)) | 297 | if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA)) |
287 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) | 298 | for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++) |
288 | if (reg_data[i].is_codec) | 299 | if (reg_data[i].is_codec) |
289 | wm8400->reg_cache[i] = reg_data[i].default_val; | 300 | wm8400->reg_cache[i] = reg_data[i].default_val; |
290 | 301 | ||
291 | ret = wm8400_read(wm8400, WM8400_ID, 1, ®); | 302 | ret = wm8400_read(wm8400, WM8400_ID, 1, ®); |
292 | if (ret != 0) { | 303 | if (ret != 0) { |
293 | dev_err(wm8400->dev, "ID register read failed: %d\n", ret); | 304 | dev_err(wm8400->dev, "ID register read failed: %d\n", ret); |
294 | return ret; | 305 | return ret; |
295 | } | 306 | } |
296 | reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT; | 307 | reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT; |
297 | dev_info(wm8400->dev, "WM8400 revision %x\n", reg); | 308 | dev_info(wm8400->dev, "WM8400 revision %x\n", reg); |
298 | 309 | ||
310 | ret = wm8400_register_codec(wm8400); | ||
311 | if (ret != 0) { | ||
312 | dev_err(wm8400->dev, "Failed to register codec\n"); | ||
313 | goto err_children; | ||
314 | } | ||
315 | |||
299 | if (pdata && pdata->platform_init) { | 316 | if (pdata && pdata->platform_init) { |
300 | ret = pdata->platform_init(wm8400->dev); | 317 | ret = pdata->platform_init(wm8400->dev); |
301 | if (ret != 0) | 318 | if (ret != 0) { |
302 | dev_err(wm8400->dev, "Platform init failed: %d\n", | 319 | dev_err(wm8400->dev, "Platform init failed: %d\n", |
303 | ret); | 320 | ret); |
321 | goto err_children; | ||
322 | } | ||
304 | } else | 323 | } else |
305 | dev_warn(wm8400->dev, "No platform initialisation supplied\n"); | 324 | dev_warn(wm8400->dev, "No platform initialisation supplied\n"); |
306 | 325 | ||
326 | return 0; | ||
327 | |||
328 | err_children: | ||
329 | mfd_remove_devices(wm8400->dev); | ||
307 | return ret; | 330 | return ret; |
308 | } | 331 | } |
309 | 332 | ||
310 | static void wm8400_release(struct wm8400 *wm8400) | 333 | static void wm8400_release(struct wm8400 *wm8400) |
311 | { | 334 | { |
312 | int i; | 335 | mfd_remove_devices(wm8400->dev); |
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 | } | 336 | } |
318 | 337 | ||
319 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 338 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
320 | static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest) | 339 | static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest) |
321 | { | 340 | { |
322 | struct i2c_client *i2c = io_data; | 341 | struct i2c_client *i2c = io_data; |
323 | struct i2c_msg xfer[2]; | 342 | struct i2c_msg xfer[2]; |
324 | int ret; | 343 | int ret; |
325 | 344 | ||
326 | /* Write register */ | 345 | /* Write register */ |
327 | xfer[0].addr = i2c->addr; | 346 | xfer[0].addr = i2c->addr; |
328 | xfer[0].flags = 0; | 347 | xfer[0].flags = 0; |
329 | xfer[0].len = 1; | 348 | xfer[0].len = 1; |
330 | xfer[0].buf = ® | 349 | xfer[0].buf = ® |
331 | 350 | ||
332 | /* Read data */ | 351 | /* Read data */ |
333 | xfer[1].addr = i2c->addr; | 352 | xfer[1].addr = i2c->addr; |
334 | xfer[1].flags = I2C_M_RD; | 353 | xfer[1].flags = I2C_M_RD; |
335 | xfer[1].len = count * sizeof(u16); | 354 | xfer[1].len = count * sizeof(u16); |
336 | xfer[1].buf = (u8 *)dest; | 355 | xfer[1].buf = (u8 *)dest; |
337 | 356 | ||
338 | ret = i2c_transfer(i2c->adapter, xfer, 2); | 357 | ret = i2c_transfer(i2c->adapter, xfer, 2); |
339 | if (ret == 2) | 358 | if (ret == 2) |
340 | ret = 0; | 359 | ret = 0; |
341 | else if (ret >= 0) | 360 | else if (ret >= 0) |
342 | ret = -EIO; | 361 | ret = -EIO; |
343 | 362 | ||
344 | return ret; | 363 | return ret; |
345 | } | 364 | } |
346 | 365 | ||
347 | static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src) | 366 | static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src) |
348 | { | 367 | { |
349 | struct i2c_client *i2c = io_data; | 368 | struct i2c_client *i2c = io_data; |
350 | u8 *msg; | 369 | u8 *msg; |
351 | int ret; | 370 | int ret; |
352 | 371 | ||
353 | /* We add 1 byte for device register - ideally I2C would gather. */ | 372 | /* We add 1 byte for device register - ideally I2C would gather. */ |
354 | msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL); | 373 | msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL); |
355 | if (msg == NULL) | 374 | if (msg == NULL) |
356 | return -ENOMEM; | 375 | return -ENOMEM; |
357 | 376 | ||
358 | msg[0] = reg; | 377 | msg[0] = reg; |
359 | memcpy(&msg[1], src, count * sizeof(u16)); | 378 | memcpy(&msg[1], src, count * sizeof(u16)); |
360 | 379 | ||
361 | ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1); | 380 | ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1); |
362 | 381 | ||
363 | if (ret == (count * 2) + 1) | 382 | if (ret == (count * 2) + 1) |
364 | ret = 0; | 383 | ret = 0; |
365 | else if (ret >= 0) | 384 | else if (ret >= 0) |
366 | ret = -EIO; | 385 | ret = -EIO; |
367 | 386 | ||
368 | kfree(msg); | 387 | kfree(msg); |
369 | 388 | ||
370 | return ret; | 389 | return ret; |
371 | } | 390 | } |
372 | 391 | ||
373 | static int wm8400_i2c_probe(struct i2c_client *i2c, | 392 | static int wm8400_i2c_probe(struct i2c_client *i2c, |
374 | const struct i2c_device_id *id) | 393 | const struct i2c_device_id *id) |
375 | { | 394 | { |
376 | struct wm8400 *wm8400; | 395 | struct wm8400 *wm8400; |
377 | int ret; | 396 | int ret; |
378 | 397 | ||
379 | wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL); | 398 | wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL); |
380 | if (wm8400 == NULL) { | 399 | if (wm8400 == NULL) { |
381 | ret = -ENOMEM; | 400 | ret = -ENOMEM; |
382 | goto err; | 401 | goto err; |
383 | } | 402 | } |
384 | 403 | ||
385 | wm8400->io_data = i2c; | 404 | wm8400->io_data = i2c; |
386 | wm8400->read_dev = wm8400_i2c_read; | 405 | wm8400->read_dev = wm8400_i2c_read; |
387 | wm8400->write_dev = wm8400_i2c_write; | 406 | wm8400->write_dev = wm8400_i2c_write; |
388 | wm8400->dev = &i2c->dev; | 407 | wm8400->dev = &i2c->dev; |
389 | i2c_set_clientdata(i2c, wm8400); | 408 | i2c_set_clientdata(i2c, wm8400); |
390 | 409 | ||
391 | ret = wm8400_init(wm8400, i2c->dev.platform_data); | 410 | ret = wm8400_init(wm8400, i2c->dev.platform_data); |
392 | if (ret != 0) | 411 | if (ret != 0) |
393 | goto struct_err; | 412 | goto struct_err; |
394 | 413 | ||
395 | return 0; | 414 | return 0; |
396 | 415 | ||
397 | struct_err: | 416 | struct_err: |
398 | i2c_set_clientdata(i2c, NULL); | 417 | i2c_set_clientdata(i2c, NULL); |
399 | kfree(wm8400); | 418 | kfree(wm8400); |
400 | err: | 419 | err: |
401 | return ret; | 420 | return ret; |
402 | } | 421 | } |
403 | 422 | ||
404 | static int wm8400_i2c_remove(struct i2c_client *i2c) | 423 | static int wm8400_i2c_remove(struct i2c_client *i2c) |
405 | { | 424 | { |
406 | struct wm8400 *wm8400 = i2c_get_clientdata(i2c); | 425 | struct wm8400 *wm8400 = i2c_get_clientdata(i2c); |
407 | 426 | ||
408 | wm8400_release(wm8400); | 427 | wm8400_release(wm8400); |
409 | i2c_set_clientdata(i2c, NULL); | 428 | i2c_set_clientdata(i2c, NULL); |
410 | kfree(wm8400); | 429 | kfree(wm8400); |
411 | 430 | ||
412 | return 0; | 431 | return 0; |
413 | } | 432 | } |
414 | 433 | ||
415 | static const struct i2c_device_id wm8400_i2c_id[] = { | 434 | static const struct i2c_device_id wm8400_i2c_id[] = { |
416 | { "wm8400", 0 }, | 435 | { "wm8400", 0 }, |
417 | { } | 436 | { } |
418 | }; | 437 | }; |
419 | MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id); | 438 | MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id); |
420 | 439 | ||
421 | static struct i2c_driver wm8400_i2c_driver = { | 440 | static struct i2c_driver wm8400_i2c_driver = { |
422 | .driver = { | 441 | .driver = { |
423 | .name = "WM8400", | 442 | .name = "WM8400", |
424 | .owner = THIS_MODULE, | 443 | .owner = THIS_MODULE, |
425 | }, | 444 | }, |
426 | .probe = wm8400_i2c_probe, | 445 | .probe = wm8400_i2c_probe, |
427 | .remove = wm8400_i2c_remove, | 446 | .remove = wm8400_i2c_remove, |
428 | .id_table = wm8400_i2c_id, | 447 | .id_table = wm8400_i2c_id, |
429 | }; | 448 | }; |
430 | #endif | 449 | #endif |
431 | 450 | ||
432 | static int __init wm8400_module_init(void) | 451 | static int __init wm8400_module_init(void) |
433 | { | 452 | { |
434 | int ret = -ENODEV; | 453 | int ret = -ENODEV; |
435 | 454 | ||
436 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 455 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
437 | ret = i2c_add_driver(&wm8400_i2c_driver); | 456 | ret = i2c_add_driver(&wm8400_i2c_driver); |
438 | if (ret != 0) | 457 | if (ret != 0) |
439 | pr_err("Failed to register I2C driver: %d\n", ret); | 458 | pr_err("Failed to register I2C driver: %d\n", ret); |
440 | #endif | 459 | #endif |
441 | 460 | ||
442 | return ret; | 461 | return ret; |
443 | } | 462 | } |
444 | module_init(wm8400_module_init); | 463 | module_init(wm8400_module_init); |
445 | 464 | ||
446 | static void __exit wm8400_module_exit(void) | 465 | static void __exit wm8400_module_exit(void) |
447 | { | 466 | { |
448 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 467 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
449 | i2c_del_driver(&wm8400_i2c_driver); | 468 | i2c_del_driver(&wm8400_i2c_driver); |
450 | #endif | 469 | #endif |
451 | } | 470 | } |
452 | module_exit(wm8400_module_exit); | 471 | module_exit(wm8400_module_exit); |