Commit ebd29c6cc0b29b4bb041441fc251e0f400eea2cf
Committed by
Samuel Ortiz
1 parent
eee0e4b44f
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
mfd: Export wm8400_block_read()
Used by the regulator driver. Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 1 changed file with 1 additions and 0 deletions Inline Diff
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/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/bug.h> | 16 | #include <linux/bug.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/mfd/core.h> | 20 | #include <linux/mfd/core.h> |
21 | #include <linux/mfd/wm8400-private.h> | 21 | #include <linux/mfd/wm8400-private.h> |
22 | #include <linux/mfd/wm8400-audio.h> | 22 | #include <linux/mfd/wm8400-audio.h> |
23 | #include <linux/regmap.h> | 23 | #include <linux/regmap.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | 25 | ||
26 | static bool wm8400_volatile(struct device *dev, unsigned int reg) | 26 | static bool wm8400_volatile(struct device *dev, unsigned int reg) |
27 | { | 27 | { |
28 | switch (reg) { | 28 | switch (reg) { |
29 | case WM8400_INTERRUPT_STATUS_1: | 29 | case WM8400_INTERRUPT_STATUS_1: |
30 | case WM8400_INTERRUPT_LEVELS: | 30 | case WM8400_INTERRUPT_LEVELS: |
31 | case WM8400_SHUTDOWN_REASON: | 31 | case WM8400_SHUTDOWN_REASON: |
32 | return true; | 32 | return true; |
33 | default: | 33 | default: |
34 | return false; | 34 | return false; |
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * wm8400_reg_read - Single register read | 39 | * wm8400_reg_read - Single register read |
40 | * | 40 | * |
41 | * @wm8400: Pointer to wm8400 control structure | 41 | * @wm8400: Pointer to wm8400 control structure |
42 | * @reg: Register to read | 42 | * @reg: Register to read |
43 | * | 43 | * |
44 | * @return Read value | 44 | * @return Read value |
45 | */ | 45 | */ |
46 | u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg) | 46 | u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg) |
47 | { | 47 | { |
48 | unsigned int val; | 48 | unsigned int val; |
49 | int ret; | 49 | int ret; |
50 | 50 | ||
51 | ret = regmap_read(wm8400->regmap, reg, &val); | 51 | ret = regmap_read(wm8400->regmap, reg, &val); |
52 | if (ret < 0) | 52 | if (ret < 0) |
53 | return ret; | 53 | return ret; |
54 | 54 | ||
55 | return val; | 55 | return val; |
56 | } | 56 | } |
57 | EXPORT_SYMBOL_GPL(wm8400_reg_read); | 57 | EXPORT_SYMBOL_GPL(wm8400_reg_read); |
58 | 58 | ||
59 | int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data) | 59 | int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data) |
60 | { | 60 | { |
61 | return regmap_bulk_read(wm8400->regmap, reg, data, count); | 61 | return regmap_bulk_read(wm8400->regmap, reg, data, count); |
62 | } | 62 | } |
63 | EXPORT_SYMBOL_GPL(wm8400_block_read); | ||
63 | 64 | ||
64 | static int wm8400_register_codec(struct wm8400 *wm8400) | 65 | static int wm8400_register_codec(struct wm8400 *wm8400) |
65 | { | 66 | { |
66 | struct mfd_cell cell = { | 67 | struct mfd_cell cell = { |
67 | .name = "wm8400-codec", | 68 | .name = "wm8400-codec", |
68 | .platform_data = wm8400, | 69 | .platform_data = wm8400, |
69 | .pdata_size = sizeof(*wm8400), | 70 | .pdata_size = sizeof(*wm8400), |
70 | }; | 71 | }; |
71 | 72 | ||
72 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); | 73 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); |
73 | } | 74 | } |
74 | 75 | ||
75 | /* | 76 | /* |
76 | * wm8400_init - Generic initialisation | 77 | * wm8400_init - Generic initialisation |
77 | * | 78 | * |
78 | * The WM8400 can be configured as either an I2C or SPI device. Probe | 79 | * The WM8400 can be configured as either an I2C or SPI device. Probe |
79 | * functions for each bus set up the accessors then call into this to | 80 | * functions for each bus set up the accessors then call into this to |
80 | * set up the device itself. | 81 | * set up the device itself. |
81 | */ | 82 | */ |
82 | static int wm8400_init(struct wm8400 *wm8400, | 83 | static int wm8400_init(struct wm8400 *wm8400, |
83 | struct wm8400_platform_data *pdata) | 84 | struct wm8400_platform_data *pdata) |
84 | { | 85 | { |
85 | unsigned int reg; | 86 | unsigned int reg; |
86 | int ret; | 87 | int ret; |
87 | 88 | ||
88 | dev_set_drvdata(wm8400->dev, wm8400); | 89 | dev_set_drvdata(wm8400->dev, wm8400); |
89 | 90 | ||
90 | /* Check that this is actually a WM8400 */ | 91 | /* Check that this is actually a WM8400 */ |
91 | ret = regmap_read(wm8400->regmap, WM8400_RESET_ID, ®); | 92 | ret = regmap_read(wm8400->regmap, WM8400_RESET_ID, ®); |
92 | if (ret != 0) { | 93 | if (ret != 0) { |
93 | dev_err(wm8400->dev, "Chip ID register read failed\n"); | 94 | dev_err(wm8400->dev, "Chip ID register read failed\n"); |
94 | return -EIO; | 95 | return -EIO; |
95 | } | 96 | } |
96 | if (reg != 0x6172) { | 97 | if (reg != 0x6172) { |
97 | dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", | 98 | dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", |
98 | reg); | 99 | reg); |
99 | return -ENODEV; | 100 | return -ENODEV; |
100 | } | 101 | } |
101 | 102 | ||
102 | ret = regmap_read(wm8400->regmap, WM8400_ID, ®); | 103 | ret = regmap_read(wm8400->regmap, WM8400_ID, ®); |
103 | if (ret != 0) { | 104 | if (ret != 0) { |
104 | dev_err(wm8400->dev, "ID register read failed: %d\n", ret); | 105 | dev_err(wm8400->dev, "ID register read failed: %d\n", ret); |
105 | return ret; | 106 | return ret; |
106 | } | 107 | } |
107 | reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT; | 108 | reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT; |
108 | dev_info(wm8400->dev, "WM8400 revision %x\n", reg); | 109 | dev_info(wm8400->dev, "WM8400 revision %x\n", reg); |
109 | 110 | ||
110 | ret = wm8400_register_codec(wm8400); | 111 | ret = wm8400_register_codec(wm8400); |
111 | if (ret != 0) { | 112 | if (ret != 0) { |
112 | dev_err(wm8400->dev, "Failed to register codec\n"); | 113 | dev_err(wm8400->dev, "Failed to register codec\n"); |
113 | goto err_children; | 114 | goto err_children; |
114 | } | 115 | } |
115 | 116 | ||
116 | if (pdata && pdata->platform_init) { | 117 | if (pdata && pdata->platform_init) { |
117 | ret = pdata->platform_init(wm8400->dev); | 118 | ret = pdata->platform_init(wm8400->dev); |
118 | if (ret != 0) { | 119 | if (ret != 0) { |
119 | dev_err(wm8400->dev, "Platform init failed: %d\n", | 120 | dev_err(wm8400->dev, "Platform init failed: %d\n", |
120 | ret); | 121 | ret); |
121 | goto err_children; | 122 | goto err_children; |
122 | } | 123 | } |
123 | } else | 124 | } else |
124 | dev_warn(wm8400->dev, "No platform initialisation supplied\n"); | 125 | dev_warn(wm8400->dev, "No platform initialisation supplied\n"); |
125 | 126 | ||
126 | return 0; | 127 | return 0; |
127 | 128 | ||
128 | err_children: | 129 | err_children: |
129 | mfd_remove_devices(wm8400->dev); | 130 | mfd_remove_devices(wm8400->dev); |
130 | return ret; | 131 | return ret; |
131 | } | 132 | } |
132 | 133 | ||
133 | static void wm8400_release(struct wm8400 *wm8400) | 134 | static void wm8400_release(struct wm8400 *wm8400) |
134 | { | 135 | { |
135 | mfd_remove_devices(wm8400->dev); | 136 | mfd_remove_devices(wm8400->dev); |
136 | } | 137 | } |
137 | 138 | ||
138 | static const struct regmap_config wm8400_regmap_config = { | 139 | static const struct regmap_config wm8400_regmap_config = { |
139 | .reg_bits = 8, | 140 | .reg_bits = 8, |
140 | .val_bits = 16, | 141 | .val_bits = 16, |
141 | .max_register = WM8400_REGISTER_COUNT - 1, | 142 | .max_register = WM8400_REGISTER_COUNT - 1, |
142 | 143 | ||
143 | .volatile_reg = wm8400_volatile, | 144 | .volatile_reg = wm8400_volatile, |
144 | 145 | ||
145 | .cache_type = REGCACHE_RBTREE, | 146 | .cache_type = REGCACHE_RBTREE, |
146 | }; | 147 | }; |
147 | 148 | ||
148 | /** | 149 | /** |
149 | * wm8400_reset_codec_reg_cache - Reset cached codec registers to | 150 | * wm8400_reset_codec_reg_cache - Reset cached codec registers to |
150 | * their default values. | 151 | * their default values. |
151 | */ | 152 | */ |
152 | void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400) | 153 | void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400) |
153 | { | 154 | { |
154 | regmap_reinit_cache(wm8400->regmap, &wm8400_regmap_config); | 155 | regmap_reinit_cache(wm8400->regmap, &wm8400_regmap_config); |
155 | } | 156 | } |
156 | EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache); | 157 | EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache); |
157 | 158 | ||
158 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 159 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
159 | static int wm8400_i2c_probe(struct i2c_client *i2c, | 160 | static int wm8400_i2c_probe(struct i2c_client *i2c, |
160 | const struct i2c_device_id *id) | 161 | const struct i2c_device_id *id) |
161 | { | 162 | { |
162 | struct wm8400 *wm8400; | 163 | struct wm8400 *wm8400; |
163 | int ret; | 164 | int ret; |
164 | 165 | ||
165 | wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL); | 166 | wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL); |
166 | if (wm8400 == NULL) { | 167 | if (wm8400 == NULL) { |
167 | ret = -ENOMEM; | 168 | ret = -ENOMEM; |
168 | goto err; | 169 | goto err; |
169 | } | 170 | } |
170 | 171 | ||
171 | wm8400->regmap = devm_regmap_init_i2c(i2c, &wm8400_regmap_config); | 172 | wm8400->regmap = devm_regmap_init_i2c(i2c, &wm8400_regmap_config); |
172 | if (IS_ERR(wm8400->regmap)) { | 173 | if (IS_ERR(wm8400->regmap)) { |
173 | ret = PTR_ERR(wm8400->regmap); | 174 | ret = PTR_ERR(wm8400->regmap); |
174 | goto err; | 175 | goto err; |
175 | } | 176 | } |
176 | 177 | ||
177 | wm8400->dev = &i2c->dev; | 178 | wm8400->dev = &i2c->dev; |
178 | i2c_set_clientdata(i2c, wm8400); | 179 | i2c_set_clientdata(i2c, wm8400); |
179 | 180 | ||
180 | ret = wm8400_init(wm8400, i2c->dev.platform_data); | 181 | ret = wm8400_init(wm8400, i2c->dev.platform_data); |
181 | if (ret != 0) | 182 | if (ret != 0) |
182 | goto err; | 183 | goto err; |
183 | 184 | ||
184 | return 0; | 185 | return 0; |
185 | 186 | ||
186 | err: | 187 | err: |
187 | return ret; | 188 | return ret; |
188 | } | 189 | } |
189 | 190 | ||
190 | static int wm8400_i2c_remove(struct i2c_client *i2c) | 191 | static int wm8400_i2c_remove(struct i2c_client *i2c) |
191 | { | 192 | { |
192 | struct wm8400 *wm8400 = i2c_get_clientdata(i2c); | 193 | struct wm8400 *wm8400 = i2c_get_clientdata(i2c); |
193 | 194 | ||
194 | wm8400_release(wm8400); | 195 | wm8400_release(wm8400); |
195 | 196 | ||
196 | return 0; | 197 | return 0; |
197 | } | 198 | } |
198 | 199 | ||
199 | static const struct i2c_device_id wm8400_i2c_id[] = { | 200 | static const struct i2c_device_id wm8400_i2c_id[] = { |
200 | { "wm8400", 0 }, | 201 | { "wm8400", 0 }, |
201 | { } | 202 | { } |
202 | }; | 203 | }; |
203 | MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id); | 204 | MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id); |
204 | 205 | ||
205 | static struct i2c_driver wm8400_i2c_driver = { | 206 | static struct i2c_driver wm8400_i2c_driver = { |
206 | .driver = { | 207 | .driver = { |
207 | .name = "WM8400", | 208 | .name = "WM8400", |
208 | .owner = THIS_MODULE, | 209 | .owner = THIS_MODULE, |
209 | }, | 210 | }, |
210 | .probe = wm8400_i2c_probe, | 211 | .probe = wm8400_i2c_probe, |
211 | .remove = wm8400_i2c_remove, | 212 | .remove = wm8400_i2c_remove, |
212 | .id_table = wm8400_i2c_id, | 213 | .id_table = wm8400_i2c_id, |
213 | }; | 214 | }; |
214 | #endif | 215 | #endif |
215 | 216 | ||
216 | static int __init wm8400_module_init(void) | 217 | static int __init wm8400_module_init(void) |
217 | { | 218 | { |
218 | int ret = -ENODEV; | 219 | int ret = -ENODEV; |
219 | 220 | ||
220 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 221 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
221 | ret = i2c_add_driver(&wm8400_i2c_driver); | 222 | ret = i2c_add_driver(&wm8400_i2c_driver); |
222 | if (ret != 0) | 223 | if (ret != 0) |
223 | pr_err("Failed to register I2C driver: %d\n", ret); | 224 | pr_err("Failed to register I2C driver: %d\n", ret); |
224 | #endif | 225 | #endif |
225 | 226 | ||
226 | return ret; | 227 | return ret; |
227 | } | 228 | } |
228 | subsys_initcall(wm8400_module_init); | 229 | subsys_initcall(wm8400_module_init); |
229 | 230 | ||
230 | static void __exit wm8400_module_exit(void) | 231 | static void __exit wm8400_module_exit(void) |
231 | { | 232 | { |
232 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 233 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
233 | i2c_del_driver(&wm8400_i2c_driver); | 234 | i2c_del_driver(&wm8400_i2c_driver); |
234 | #endif | 235 | #endif |
235 | } | 236 | } |
236 | module_exit(wm8400_module_exit); | 237 | module_exit(wm8400_module_exit); |
237 | 238 | ||
238 | MODULE_LICENSE("GPL"); | 239 | MODULE_LICENSE("GPL"); |
239 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 240 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
240 | 241 |