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