1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Speyside modules for Cragganmore - board data probing |
4 | // |
5 | // Copyright 2011 Wolfson Microelectronics plc |
6 | // Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | |
8 | #include <linux/export.h> |
9 | #include <linux/interrupt.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/spi/spi.h> |
12 | #include <linux/gpio/machine.h> |
13 | |
14 | #include <linux/mfd/wm831x/irq.h> |
15 | #include <linux/mfd/wm831x/gpio.h> |
16 | #include <linux/mfd/wm8994/pdata.h> |
17 | #include <linux/mfd/arizona/pdata.h> |
18 | |
19 | #include <linux/regulator/machine.h> |
20 | |
21 | #include <sound/wm0010.h> |
22 | #include <sound/wm2200.h> |
23 | #include <sound/wm5100.h> |
24 | #include <sound/wm8996.h> |
25 | #include <sound/wm8962.h> |
26 | #include <sound/wm9081.h> |
27 | |
28 | #include <linux/platform_data/spi-s3c64xx.h> |
29 | |
30 | #include "cpu.h" |
31 | #include "irqs.h" |
32 | |
33 | #include "crag6410.h" |
34 | |
35 | static struct wm0010_pdata wm0010_pdata = { |
36 | .gpio_reset = S3C64XX_GPN(6), |
37 | .reset_active_high = 1, /* Active high for Glenfarclas Rev 2 */ |
38 | }; |
39 | |
40 | static struct spi_board_info wm1253_devs[] = { |
41 | [0] = { |
42 | .modalias = "wm0010" , |
43 | .max_speed_hz = 26 * 1000 * 1000, |
44 | .bus_num = 0, |
45 | .chip_select = 0, |
46 | .mode = SPI_MODE_0, |
47 | .irq = S3C_EINT(4), |
48 | .platform_data = &wm0010_pdata, |
49 | }, |
50 | }; |
51 | |
52 | static struct spi_board_info balblair_devs[] = { |
53 | [0] = { |
54 | .modalias = "wm0010" , |
55 | .max_speed_hz = 26 * 1000 * 1000, |
56 | .bus_num = 0, |
57 | .chip_select = 0, |
58 | .mode = SPI_MODE_0, |
59 | .irq = S3C_EINT(4), |
60 | .platform_data = &wm0010_pdata, |
61 | }, |
62 | }; |
63 | |
64 | static struct wm5100_pdata wm5100_pdata = { |
65 | .ldo_ena = S3C64XX_GPN(7), |
66 | .irq_flags = IRQF_TRIGGER_HIGH, |
67 | .gpio_base = CODEC_GPIO_BASE, |
68 | |
69 | .in_mode = { |
70 | WM5100_IN_DIFF, |
71 | WM5100_IN_DIFF, |
72 | WM5100_IN_DIFF, |
73 | WM5100_IN_SE, |
74 | }, |
75 | |
76 | .hp_pol = CODEC_GPIO_BASE + 3, |
77 | .jack_modes = { |
78 | { WM5100_MICDET_MICBIAS3, 0, 0 }, |
79 | { WM5100_MICDET_MICBIAS2, 1, 1 }, |
80 | }, |
81 | |
82 | .gpio_defaults = { |
83 | 0, |
84 | 0, |
85 | 0, |
86 | 0, |
87 | 0x2, /* IRQ: CMOS output */ |
88 | 0x3, /* CLKOUT: CMOS output */ |
89 | }, |
90 | }; |
91 | |
92 | static struct wm8996_retune_mobile_config wm8996_retune[] = { |
93 | { |
94 | .name = "Sub LPF" , |
95 | .rate = 48000, |
96 | .regs = { |
97 | 0x6318, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, |
98 | 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, |
99 | 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 |
100 | }, |
101 | }, |
102 | { |
103 | .name = "Sub HPF" , |
104 | .rate = 48000, |
105 | .regs = { |
106 | 0x000A, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, |
107 | 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, |
108 | 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 |
109 | }, |
110 | }, |
111 | }; |
112 | |
113 | static struct wm8996_pdata wm8996_pdata __initdata = { |
114 | .ldo_ena = S3C64XX_GPN(7), |
115 | .gpio_base = CODEC_GPIO_BASE, |
116 | .micdet_def = 1, |
117 | .inl_mode = WM8996_DIFFERRENTIAL_1, |
118 | .inr_mode = WM8996_DIFFERRENTIAL_1, |
119 | |
120 | .irq_flags = IRQF_TRIGGER_RISING, |
121 | |
122 | .gpio_default = { |
123 | 0x8001, /* GPIO1 == ADCLRCLK1 */ |
124 | 0x8001, /* GPIO2 == ADCLRCLK2, input due to CPU */ |
125 | 0x0141, /* GPIO3 == HP_SEL */ |
126 | 0x0002, /* GPIO4 == IRQ */ |
127 | 0x020e, /* GPIO5 == CLKOUT */ |
128 | }, |
129 | |
130 | .retune_mobile_cfgs = wm8996_retune, |
131 | .num_retune_mobile_cfgs = ARRAY_SIZE(wm8996_retune), |
132 | }; |
133 | |
134 | static struct wm8962_pdata wm8962_pdata __initdata = { |
135 | .gpio_init = { |
136 | 0, |
137 | WM8962_GPIO_FN_OPCLK, |
138 | WM8962_GPIO_FN_DMICCLK, |
139 | 0, |
140 | 0x8000 | WM8962_GPIO_FN_DMICDAT, |
141 | WM8962_GPIO_FN_IRQ, /* Open drain mode */ |
142 | }, |
143 | .in4_dc_measure = true, |
144 | }; |
145 | |
146 | static struct wm9081_pdata wm9081_pdata __initdata = { |
147 | .irq_high = false, |
148 | .irq_cmos = false, |
149 | }; |
150 | |
151 | static const struct i2c_board_info wm1254_devs[] = { |
152 | { I2C_BOARD_INFO("wm8996" , 0x1a), |
153 | .platform_data = &wm8996_pdata, |
154 | .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, |
155 | }, |
156 | { I2C_BOARD_INFO("wm9081" , 0x6c), |
157 | .platform_data = &wm9081_pdata, }, |
158 | }; |
159 | |
160 | static const struct i2c_board_info wm1255_devs[] = { |
161 | { I2C_BOARD_INFO("wm5100" , 0x1a), |
162 | .platform_data = &wm5100_pdata, |
163 | .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, |
164 | }, |
165 | { I2C_BOARD_INFO("wm9081" , 0x6c), |
166 | .platform_data = &wm9081_pdata, }, |
167 | }; |
168 | |
169 | static const struct i2c_board_info wm1259_devs[] = { |
170 | { I2C_BOARD_INFO("wm8962" , 0x1a), |
171 | .platform_data = &wm8962_pdata, |
172 | .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, |
173 | }, |
174 | }; |
175 | |
176 | static struct regulator_init_data wm8994_ldo1 = { |
177 | .supply_regulator = "WALLVDD" , |
178 | }; |
179 | |
180 | static struct regulator_init_data wm8994_ldo2 = { |
181 | .supply_regulator = "WALLVDD" , |
182 | }; |
183 | |
184 | static struct wm8994_pdata wm8994_pdata = { |
185 | .gpio_base = CODEC_GPIO_BASE, |
186 | .micb2_delay = 150, |
187 | .gpio_defaults = { |
188 | 0x3, /* IRQ out, active high, CMOS */ |
189 | }, |
190 | .ldo = { |
191 | { .init_data = &wm8994_ldo1, }, |
192 | { .init_data = &wm8994_ldo2, }, |
193 | }, |
194 | }; |
195 | |
196 | static const struct i2c_board_info wm1277_devs[] = { |
197 | { I2C_BOARD_INFO("wm8958" , 0x1a), /* WM8958 is the superset */ |
198 | .platform_data = &wm8994_pdata, |
199 | .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, |
200 | .dev_name = "wm8958" , |
201 | }, |
202 | }; |
203 | |
204 | static struct gpiod_lookup_table wm8994_gpiod_table = { |
205 | .dev_id = "i2c-wm8958" , /* I2C device name */ |
206 | .table = { |
207 | GPIO_LOOKUP("GPION" , 6, |
208 | "wlf,ldo1ena" , GPIO_ACTIVE_HIGH), |
209 | GPIO_LOOKUP("GPION" , 4, |
210 | "wlf,ldo2ena" , GPIO_ACTIVE_HIGH), |
211 | { }, |
212 | }, |
213 | }; |
214 | |
215 | static struct arizona_pdata wm5102_reva_pdata = { |
216 | .gpio_base = CODEC_GPIO_BASE, |
217 | .irq_flags = IRQF_TRIGGER_HIGH, |
218 | .micd_pol_gpio = CODEC_GPIO_BASE + 4, |
219 | .micd_rate = 6, |
220 | .gpio_defaults = { |
221 | [2] = 0x10000, /* AIF3TXLRCLK */ |
222 | [3] = 0x4, /* OPCLK */ |
223 | }, |
224 | }; |
225 | |
226 | static struct spi_board_info wm5102_reva_spi_devs[] = { |
227 | [0] = { |
228 | .modalias = "wm5102" , |
229 | .max_speed_hz = 10 * 1000 * 1000, |
230 | .bus_num = 0, |
231 | .chip_select = 1, |
232 | .mode = SPI_MODE_0, |
233 | .irq = GLENFARCLAS_PMIC_IRQ_BASE + |
234 | WM831X_IRQ_GPIO_2, |
235 | .platform_data = &wm5102_reva_pdata, |
236 | }, |
237 | }; |
238 | |
239 | static struct gpiod_lookup_table wm5102_reva_gpiod_table = { |
240 | .dev_id = "spi0.1" , /* SPI device name */ |
241 | .table = { |
242 | GPIO_LOOKUP("GPION" , 7, |
243 | "wlf,ldoena" , GPIO_ACTIVE_HIGH), |
244 | { }, |
245 | }, |
246 | }; |
247 | |
248 | static struct arizona_pdata wm5102_pdata = { |
249 | .gpio_base = CODEC_GPIO_BASE, |
250 | .irq_flags = IRQF_TRIGGER_HIGH, |
251 | .micd_pol_gpio = CODEC_GPIO_BASE + 2, |
252 | .gpio_defaults = { |
253 | [2] = 0x10000, /* AIF3TXLRCLK */ |
254 | [3] = 0x4, /* OPCLK */ |
255 | }, |
256 | }; |
257 | |
258 | static struct spi_board_info wm5102_spi_devs[] = { |
259 | [0] = { |
260 | .modalias = "wm5102" , |
261 | .max_speed_hz = 10 * 1000 * 1000, |
262 | .bus_num = 0, |
263 | .chip_select = 1, |
264 | .mode = SPI_MODE_0, |
265 | .irq = GLENFARCLAS_PMIC_IRQ_BASE + |
266 | WM831X_IRQ_GPIO_2, |
267 | .platform_data = &wm5102_pdata, |
268 | }, |
269 | }; |
270 | |
271 | static struct gpiod_lookup_table wm5102_gpiod_table = { |
272 | .dev_id = "spi0.1" , /* SPI device name */ |
273 | .table = { |
274 | GPIO_LOOKUP("GPION" , 7, |
275 | "wlf,ldo1ena" , GPIO_ACTIVE_HIGH), |
276 | { }, |
277 | }, |
278 | }; |
279 | |
280 | static struct spi_board_info wm5110_spi_devs[] = { |
281 | [0] = { |
282 | .modalias = "wm5110" , |
283 | .max_speed_hz = 10 * 1000 * 1000, |
284 | .bus_num = 0, |
285 | .chip_select = 1, |
286 | .mode = SPI_MODE_0, |
287 | .irq = GLENFARCLAS_PMIC_IRQ_BASE + |
288 | WM831X_IRQ_GPIO_2, |
289 | .platform_data = &wm5102_reva_pdata, |
290 | }, |
291 | }; |
292 | |
293 | static const struct i2c_board_info wm6230_i2c_devs[] = { |
294 | { I2C_BOARD_INFO("wm9081" , 0x6c), |
295 | .platform_data = &wm9081_pdata, }, |
296 | }; |
297 | |
298 | static struct wm2200_pdata wm2200_pdata = { |
299 | .ldo_ena = S3C64XX_GPN(7), |
300 | .gpio_defaults = { |
301 | [2] = 0x0005, /* GPIO3 24.576MHz output clock */ |
302 | }, |
303 | }; |
304 | |
305 | static const struct i2c_board_info wm2200_i2c[] = { |
306 | { I2C_BOARD_INFO("wm2200" , 0x3a), |
307 | .platform_data = &wm2200_pdata, }, |
308 | }; |
309 | |
310 | static const struct { |
311 | u8 id; |
312 | u8 rev; |
313 | const char *name; |
314 | const struct i2c_board_info *i2c_devs; |
315 | int num_i2c_devs; |
316 | const struct spi_board_info *spi_devs; |
317 | int num_spi_devs; |
318 | |
319 | struct gpiod_lookup_table *gpiod_table; |
320 | } gf_mods[] = { |
321 | { .id = 0x01, .rev = 0xff, .name = "1250-EV1 Springbank" }, |
322 | { .id = 0x02, .rev = 0xff, .name = "1251-EV1 Jura" }, |
323 | { .id = 0x03, .rev = 0xff, .name = "1252-EV1 Glenlivet" }, |
324 | { .id = 0x06, .rev = 0xff, .name = "WM8997-6721-CS96-EV1 Lapraoig" }, |
325 | { .id = 0x07, .rev = 0xff, .name = "WM5110-6271 Deanston" , |
326 | .spi_devs = wm5110_spi_devs, |
327 | .num_spi_devs = ARRAY_SIZE(wm5110_spi_devs) }, |
328 | { .id = 0x08, .rev = 0xff, .name = "WM8903-6102 Tamdhu" }, |
329 | { .id = 0x09, .rev = 0xff, .name = "WM1811A-6305 Adelphi" }, |
330 | { .id = 0x0a, .rev = 0xff, .name = "WM8996-6272 Blackadder" }, |
331 | { .id = 0x0b, .rev = 0xff, .name = "WM8994-6235 Benromach" }, |
332 | { .id = 0x11, .rev = 0xff, .name = "6249-EV2 Glenfarclas" , }, |
333 | { .id = 0x14, .rev = 0xff, .name = "6271-EV1 Lochnagar" }, |
334 | { .id = 0x15, .rev = 0xff, .name = "6320-EV1 Bells" , |
335 | .i2c_devs = wm6230_i2c_devs, |
336 | .num_i2c_devs = ARRAY_SIZE(wm6230_i2c_devs) }, |
337 | { .id = 0x21, .rev = 0xff, .name = "1275-EV1 Mortlach" }, |
338 | { .id = 0x25, .rev = 0xff, .name = "1274-EV1 Glencadam" }, |
339 | { .id = 0x31, .rev = 0xff, .name = "1253-EV1 Tomatin" , |
340 | .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) }, |
341 | { .id = 0x32, .rev = 0xff, .name = "XXXX-EV1 Caol Illa" }, |
342 | { .id = 0x33, .rev = 0xff, .name = "XXXX-EV1 Oban" }, |
343 | { .id = 0x34, .rev = 0xff, .name = "WM0010-6320-CS42 Balblair" , |
344 | .spi_devs = balblair_devs, |
345 | .num_spi_devs = ARRAY_SIZE(balblair_devs) }, |
346 | { .id = 0x39, .rev = 0xff, .name = "1254-EV1 Dallas Dhu" , |
347 | .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) }, |
348 | { .id = 0x3a, .rev = 0xff, .name = "1259-EV1 Tobermory" , |
349 | .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) }, |
350 | { .id = 0x3b, .rev = 0xff, .name = "1255-EV1 Kilchoman" , |
351 | .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs) }, |
352 | { .id = 0x3c, .rev = 0xff, .name = "1273-EV1 Longmorn" }, |
353 | { .id = 0x3d, .rev = 0xff, .name = "1277-EV1 Littlemill" , |
354 | .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs), |
355 | .gpiod_table = &wm8994_gpiod_table }, |
356 | { .id = 0x3e, .rev = 0, .name = "WM5102-6271-EV1-CS127 Amrut" , |
357 | .spi_devs = wm5102_reva_spi_devs, |
358 | .num_spi_devs = ARRAY_SIZE(wm5102_reva_spi_devs), |
359 | .gpiod_table = &wm5102_reva_gpiod_table }, |
360 | { .id = 0x3e, .rev = -1, .name = "WM5102-6271-EV1-CS127 Amrut" , |
361 | .spi_devs = wm5102_spi_devs, |
362 | .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs), |
363 | .gpiod_table = &wm5102_gpiod_table }, |
364 | { .id = 0x3f, .rev = -1, .name = "WM2200-6271-CS90-M-REV1" , |
365 | .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c) }, |
366 | }; |
367 | |
368 | static int wlf_gf_module_probe(struct i2c_client *i2c) |
369 | { |
370 | int ret, i, j, id, rev; |
371 | |
372 | ret = i2c_smbus_read_byte_data(client: i2c, command: 0); |
373 | if (ret < 0) { |
374 | dev_err(&i2c->dev, "Failed to read ID: %d\n" , ret); |
375 | return ret; |
376 | } |
377 | |
378 | id = (ret & 0xfe) >> 2; |
379 | rev = ret & 0x3; |
380 | for (i = 0; i < ARRAY_SIZE(gf_mods); i++) |
381 | if (id == gf_mods[i].id && (gf_mods[i].rev == 0xff || |
382 | rev == gf_mods[i].rev)) |
383 | break; |
384 | |
385 | gpiod_add_lookup_table(table: &wm5102_reva_gpiod_table); |
386 | gpiod_add_lookup_table(table: &wm5102_gpiod_table); |
387 | gpiod_add_lookup_table(table: &wm8994_gpiod_table); |
388 | |
389 | if (i < ARRAY_SIZE(gf_mods)) { |
390 | dev_info(&i2c->dev, "%s revision %d\n" , |
391 | gf_mods[i].name, rev + 1); |
392 | |
393 | for (j = 0; j < gf_mods[i].num_i2c_devs; j++) { |
394 | if (IS_ERR(ptr: i2c_new_client_device(adap: i2c->adapter, |
395 | info: &(gf_mods[i].i2c_devs[j])))) |
396 | dev_err(&i2c->dev, "Failed to register\n" ); |
397 | } |
398 | |
399 | spi_register_board_info(info: gf_mods[i].spi_devs, |
400 | n: gf_mods[i].num_spi_devs); |
401 | |
402 | if (gf_mods[i].gpiod_table) |
403 | gpiod_add_lookup_table(table: gf_mods[i].gpiod_table); |
404 | } else { |
405 | dev_warn(&i2c->dev, "Unknown module ID 0x%x revision %d\n" , |
406 | id, rev + 1); |
407 | } |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | static const struct i2c_device_id wlf_gf_module_id[] = { |
413 | { "wlf-gf-module" , 0 }, |
414 | { } |
415 | }; |
416 | |
417 | static struct i2c_driver wlf_gf_module_driver = { |
418 | .driver = { |
419 | .name = "wlf-gf-module" |
420 | }, |
421 | .probe = wlf_gf_module_probe, |
422 | .id_table = wlf_gf_module_id, |
423 | }; |
424 | |
425 | static int __init wlf_gf_module_register(void) |
426 | { |
427 | if (!soc_is_s3c64xx()) |
428 | return 0; |
429 | |
430 | return i2c_add_driver(&wlf_gf_module_driver); |
431 | } |
432 | device_initcall(wlf_gf_module_register); |
433 | |