xref: /openbmc/linux/drivers/mfd/arizona-spi.c (revision 1815d400)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a15123c7SMark Brown /*
3a15123c7SMark Brown  * arizona-spi.c  --  Arizona SPI bus interface
4a15123c7SMark Brown  *
5a15123c7SMark Brown  * Copyright 2012 Wolfson Microelectronics plc
6a15123c7SMark Brown  *
7a15123c7SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8a15123c7SMark Brown  */
9a15123c7SMark Brown 
10e9338367SHans de Goede #include <linux/acpi.h>
11a15123c7SMark Brown #include <linux/err.h>
12e9338367SHans de Goede #include <linux/gpio/consumer.h>
13e9338367SHans de Goede #include <linux/gpio/machine.h>
14a15123c7SMark Brown #include <linux/module.h>
15a15123c7SMark Brown #include <linux/pm_runtime.h>
16a15123c7SMark Brown #include <linux/regmap.h>
17a15123c7SMark Brown #include <linux/regulator/consumer.h>
18a15123c7SMark Brown #include <linux/slab.h>
19a15123c7SMark Brown #include <linux/spi/spi.h>
203d6d1d1cSSachin Kamat #include <linux/of.h>
21e9338367SHans de Goede #include <uapi/linux/input-event-codes.h>
22a15123c7SMark Brown 
23a15123c7SMark Brown #include <linux/mfd/arizona/core.h>
24a15123c7SMark Brown 
25a15123c7SMark Brown #include "arizona.h"
26a15123c7SMark Brown 
27e9338367SHans de Goede #ifdef CONFIG_ACPI
28c4d09226SWei Yongjun static const struct acpi_gpio_params reset_gpios = { 1, 0, false };
29c4d09226SWei Yongjun static const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };
30e9338367SHans de Goede 
31e9338367SHans de Goede static const struct acpi_gpio_mapping arizona_acpi_gpios[] = {
32e9338367SHans de Goede 	{ "reset-gpios", &reset_gpios, 1, },
33e9338367SHans de Goede 	{ "wlf,ldoena-gpios", &ldoena_gpios, 1 },
34e9338367SHans de Goede 	{ }
35e9338367SHans de Goede };
36e9338367SHans de Goede 
37e9338367SHans de Goede /*
38e9338367SHans de Goede  * The ACPI resources for the device only describe external GPIO-s. They do
39e9338367SHans de Goede  * not provide mappings for the GPIO-s coming from the Arizona codec itself.
40e9338367SHans de Goede  */
41e9338367SHans de Goede static const struct gpiod_lookup arizona_soc_gpios[] = {
42e9338367SHans de Goede 	{ "arizona", 2, "wlf,spkvdd-ena", 0, GPIO_ACTIVE_HIGH },
43e9338367SHans de Goede 	{ "arizona", 4, "wlf,micd-pol", 0, GPIO_ACTIVE_LOW },
44e9338367SHans de Goede };
45e9338367SHans de Goede 
arizona_spi_acpi_remove_lookup(void * lookup)46e9338367SHans de Goede static void arizona_spi_acpi_remove_lookup(void *lookup)
47e9338367SHans de Goede {
48e9338367SHans de Goede 	gpiod_remove_lookup_table(lookup);
49e9338367SHans de Goede }
50e9338367SHans de Goede 
513cf2b434SHans de Goede /* For ACPI tables from boards which ship with Windows as factory OS */
arizona_spi_acpi_windows_probe(struct arizona * arizona)523cf2b434SHans de Goede static int arizona_spi_acpi_windows_probe(struct arizona *arizona)
53e9338367SHans de Goede {
54e9338367SHans de Goede 	struct gpiod_lookup_table *lookup;
55e9338367SHans de Goede 	acpi_status status;
56e9338367SHans de Goede 	int ret;
57e9338367SHans de Goede 
58e9338367SHans de Goede 	/* Add mappings for the 2 ACPI declared GPIOs used for reset and ldo-ena */
59e9338367SHans de Goede 	devm_acpi_dev_add_driver_gpios(arizona->dev, arizona_acpi_gpios);
60e9338367SHans de Goede 
61e9338367SHans de Goede 	/* Add lookups for the SoCs own GPIOs used for micdet-polarity and spkVDD-enable */
62e9338367SHans de Goede 	lookup = devm_kzalloc(arizona->dev,
63e9338367SHans de Goede 			      struct_size(lookup, table, ARRAY_SIZE(arizona_soc_gpios) + 1),
64e9338367SHans de Goede 			      GFP_KERNEL);
65e9338367SHans de Goede 	if (!lookup)
66e9338367SHans de Goede 		return -ENOMEM;
67e9338367SHans de Goede 
68e9338367SHans de Goede 	lookup->dev_id = dev_name(arizona->dev);
69e9338367SHans de Goede 	memcpy(lookup->table, arizona_soc_gpios, sizeof(arizona_soc_gpios));
70e9338367SHans de Goede 
71e9338367SHans de Goede 	gpiod_add_lookup_table(lookup);
72e9338367SHans de Goede 	ret = devm_add_action_or_reset(arizona->dev, arizona_spi_acpi_remove_lookup, lookup);
73e9338367SHans de Goede 	if (ret)
74e9338367SHans de Goede 		return ret;
75e9338367SHans de Goede 
76e9338367SHans de Goede 	/* Enable 32KHz clock from SoC to codec for jack-detect */
77e9338367SHans de Goede 	status = acpi_evaluate_object(ACPI_HANDLE(arizona->dev), "CLKE", NULL, NULL);
78e9338367SHans de Goede 	if (ACPI_FAILURE(status))
79e9338367SHans de Goede 		dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status);
80e9338367SHans de Goede 
813cf2b434SHans de Goede 	return 0;
823cf2b434SHans de Goede }
833cf2b434SHans de Goede 
849ed55e9aSHans de Goede /* For ACPI tables from boards which ship with Android as factory OS */
arizona_spi_acpi_android_probe(struct arizona * arizona)859ed55e9aSHans de Goede static int arizona_spi_acpi_android_probe(struct arizona *arizona)
869ed55e9aSHans de Goede {
879ed55e9aSHans de Goede 	int ret;
889ed55e9aSHans de Goede 
899ed55e9aSHans de Goede 	/*
909ed55e9aSHans de Goede 	 * Get the reset GPIO, treating -ENOENT as -EPROBE_DEFER to wait for
919ed55e9aSHans de Goede 	 * the x86-android-tablets module to register the board specific GPIO
929ed55e9aSHans de Goede 	 * lookup table.
939ed55e9aSHans de Goede 	 */
949ed55e9aSHans de Goede 	arizona->pdata.reset = devm_gpiod_get(arizona->dev, "reset", GPIOD_OUT_LOW);
959ed55e9aSHans de Goede 	if (IS_ERR(arizona->pdata.reset)) {
969ed55e9aSHans de Goede 		ret = PTR_ERR(arizona->pdata.reset);
979ed55e9aSHans de Goede 		if (ret == -ENOENT) {
989ed55e9aSHans de Goede 			dev_info_once(arizona->dev,
999ed55e9aSHans de Goede 				      "Deferring probe till GPIO lookup is registered\n");
1009ed55e9aSHans de Goede 			ret = -EPROBE_DEFER;
1019ed55e9aSHans de Goede 		}
1029ed55e9aSHans de Goede 		return dev_err_probe(arizona->dev, ret, "getting reset GPIO\n");
1039ed55e9aSHans de Goede 	}
1049ed55e9aSHans de Goede 
1059ed55e9aSHans de Goede 	return 0;
1069ed55e9aSHans de Goede }
1079ed55e9aSHans de Goede 
1083cf2b434SHans de Goede /*
1093cf2b434SHans de Goede  * The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
1103cf2b434SHans de Goede  * Function A Play/Pause:           0 ohm
1113cf2b434SHans de Goede  * Function D Voice assistant:    135 ohm
1123cf2b434SHans de Goede  * Function B Volume Up           240 ohm
1133cf2b434SHans de Goede  * Function C Volume Down         470 ohm
1143cf2b434SHans de Goede  * Minimum Mic DC resistance     1000 ohm
1153cf2b434SHans de Goede  * Minimum Ear speaker impedance   16 ohm
1163cf2b434SHans de Goede  * Note the first max value below must be less then the min. speaker impedance,
1173cf2b434SHans de Goede  * to allow CTIA/OMTP detection to work. The other max values are the closest
1183cf2b434SHans de Goede  * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
1193cf2b434SHans de Goede  */
1203cf2b434SHans de Goede static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {
1213cf2b434SHans de Goede 	{ .max =  11, .key = KEY_PLAYPAUSE },
1223cf2b434SHans de Goede 	{ .max = 186, .key = KEY_VOICECOMMAND },
1233cf2b434SHans de Goede 	{ .max = 348, .key = KEY_VOLUMEUP },
1243cf2b434SHans de Goede 	{ .max = 752, .key = KEY_VOLUMEDOWN },
1253cf2b434SHans de Goede };
1263cf2b434SHans de Goede 
arizona_spi_acpi_probe(struct arizona * arizona)1273cf2b434SHans de Goede static int arizona_spi_acpi_probe(struct arizona *arizona)
1283cf2b434SHans de Goede {
1299ed55e9aSHans de Goede 	struct acpi_device *adev = ACPI_COMPANION(arizona->dev);
1303cf2b434SHans de Goede 	int ret;
1313cf2b434SHans de Goede 
1329ed55e9aSHans de Goede 	if (acpi_dev_hid_uid_match(adev, "10WM5102", NULL))
1339ed55e9aSHans de Goede 		ret = arizona_spi_acpi_android_probe(arizona);
1349ed55e9aSHans de Goede 	else
1353cf2b434SHans de Goede 		ret = arizona_spi_acpi_windows_probe(arizona);
1369ed55e9aSHans de Goede 
1373cf2b434SHans de Goede 	if (ret)
1383cf2b434SHans de Goede 		return ret;
1393cf2b434SHans de Goede 
140e9338367SHans de Goede 	/*
141e9338367SHans de Goede 	 * Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING
142e9338367SHans de Goede 	 * The IRQ line will stay low when a new IRQ event happens between reading
143e9338367SHans de Goede 	 * the IRQ status flags and acknowledging them. When the IRQ line stays
144e9338367SHans de Goede 	 * low like this the IRQ will never trigger again when its type is set
145e9338367SHans de Goede 	 * to IRQF_TRIGGER_FALLING. Correct the IRQ trigger-type to fix this.
146e9338367SHans de Goede 	 *
147e9338367SHans de Goede 	 * Note theoretically it is possible that some boards are not capable
148e9338367SHans de Goede 	 * of handling active low level interrupts. In that case setting the
149e9338367SHans de Goede 	 * flag to IRQF_TRIGGER_FALLING would not be a bug (and we would need
150e9338367SHans de Goede 	 * to work around this) but so far all known usages of IRQF_TRIGGER_FALLING
151e9338367SHans de Goede 	 * are a bug in the board's DSDT.
152e9338367SHans de Goede 	 */
153e9338367SHans de Goede 	arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;
154e9338367SHans de Goede 
155e9338367SHans de Goede 	/* Wait 200 ms after jack insertion */
156e9338367SHans de Goede 	arizona->pdata.micd_detect_debounce = 200;
157e9338367SHans de Goede 
158e9338367SHans de Goede 	/* Use standard AOSP values for headset-button mappings */
159e9338367SHans de Goede 	arizona->pdata.micd_ranges = arizona_micd_aosp_ranges;
160e9338367SHans de Goede 	arizona->pdata.num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges);
161e9338367SHans de Goede 
162*1815d400SHans de Goede 	/* Use left headphone speaker for HP vs line-out detection */
163*1815d400SHans de Goede 	arizona->pdata.hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
164*1815d400SHans de Goede 
165e9338367SHans de Goede 	return 0;
166e9338367SHans de Goede }
167e9338367SHans de Goede 
168e9338367SHans de Goede static const struct acpi_device_id arizona_acpi_match[] = {
169e9338367SHans de Goede 	{
170e9338367SHans de Goede 		.id = "WM510204",
171e9338367SHans de Goede 		.driver_data = WM5102,
172e9338367SHans de Goede 	},
173e9338367SHans de Goede 	{
174e9338367SHans de Goede 		.id = "WM510205",
175e9338367SHans de Goede 		.driver_data = WM5102,
176e9338367SHans de Goede 	},
1779ed55e9aSHans de Goede 	{
1789ed55e9aSHans de Goede 		.id = "10WM5102",
1799ed55e9aSHans de Goede 		.driver_data = WM5102,
1809ed55e9aSHans de Goede 	},
181e9338367SHans de Goede 	{ }
182e9338367SHans de Goede };
183e9338367SHans de Goede MODULE_DEVICE_TABLE(acpi, arizona_acpi_match);
184e9338367SHans de Goede #else
arizona_spi_acpi_probe(struct arizona * arizona)185e9338367SHans de Goede static int arizona_spi_acpi_probe(struct arizona *arizona)
186e9338367SHans de Goede {
187e9338367SHans de Goede 	return -ENODEV;
188e9338367SHans de Goede }
189e9338367SHans de Goede #endif
190e9338367SHans de Goede 
arizona_spi_probe(struct spi_device * spi)191f791be49SBill Pemberton static int arizona_spi_probe(struct spi_device *spi)
192a15123c7SMark Brown {
193a15123c7SMark Brown 	const struct spi_device_id *id = spi_get_device_id(spi);
194039da225SHans de Goede 	const void *match_data;
195a15123c7SMark Brown 	struct arizona *arizona;
196b61c1ec0SRichard Fitzgerald 	const struct regmap_config *regmap_config = NULL;
197039da225SHans de Goede 	unsigned long type = 0;
198942786e6SLee Jones 	int ret;
199a15123c7SMark Brown 
200039da225SHans de Goede 	match_data = device_get_match_data(&spi->dev);
201039da225SHans de Goede 	if (match_data)
202039da225SHans de Goede 		type = (unsigned long)match_data;
203039da225SHans de Goede 	else if (id)
204d781009cSMark Brown 		type = id->driver_data;
205d781009cSMark Brown 
206d781009cSMark Brown 	switch (type) {
207a15123c7SMark Brown 	case WM5102:
208b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5102))
209a15123c7SMark Brown 			regmap_config = &wm5102_spi_regmap;
210a15123c7SMark Brown 		break;
211e102befeSMark Brown 	case WM5110:
212e5d4ef0dSRichard Fitzgerald 	case WM8280:
213b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5110))
214e102befeSMark Brown 			regmap_config = &wm5110_spi_regmap;
215e102befeSMark Brown 		break;
216ea1f3339SRichard Fitzgerald 	case WM1831:
217ea1f3339SRichard Fitzgerald 	case CS47L24:
218ea1f3339SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_CS47L24))
219ea1f3339SRichard Fitzgerald 			regmap_config = &cs47l24_spi_regmap;
220ea1f3339SRichard Fitzgerald 		break;
221a15123c7SMark Brown 	default:
2222e44e28aSRichard Fitzgerald 		dev_err(&spi->dev, "Unknown device type %ld\n", type);
223a15123c7SMark Brown 		return -EINVAL;
224a15123c7SMark Brown 	}
225a15123c7SMark Brown 
226b61c1ec0SRichard Fitzgerald 	if (!regmap_config) {
227b61c1ec0SRichard Fitzgerald 		dev_err(&spi->dev,
228b61c1ec0SRichard Fitzgerald 			"No kernel support for device type %ld\n", type);
229a15123c7SMark Brown 		return -EINVAL;
230a15123c7SMark Brown 	}
231a15123c7SMark Brown 
232a15123c7SMark Brown 	arizona = devm_kzalloc(&spi->dev, sizeof(*arizona), GFP_KERNEL);
233a15123c7SMark Brown 	if (arizona == NULL)
234a15123c7SMark Brown 		return -ENOMEM;
235a15123c7SMark Brown 
236a15123c7SMark Brown 	arizona->regmap = devm_regmap_init_spi(spi, regmap_config);
237a15123c7SMark Brown 	if (IS_ERR(arizona->regmap)) {
238a15123c7SMark Brown 		ret = PTR_ERR(arizona->regmap);
239a15123c7SMark Brown 		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
240a15123c7SMark Brown 			ret);
241a15123c7SMark Brown 		return ret;
242a15123c7SMark Brown 	}
243a15123c7SMark Brown 
2442e44e28aSRichard Fitzgerald 	arizona->type = type;
245a15123c7SMark Brown 	arizona->dev = &spi->dev;
246a15123c7SMark Brown 	arizona->irq = spi->irq;
247a15123c7SMark Brown 
248e9338367SHans de Goede 	if (has_acpi_companion(&spi->dev)) {
249e9338367SHans de Goede 		ret = arizona_spi_acpi_probe(arizona);
250e9338367SHans de Goede 		if (ret)
251e9338367SHans de Goede 			return ret;
252e9338367SHans de Goede 	}
253e9338367SHans de Goede 
254a15123c7SMark Brown 	return arizona_dev_init(arizona);
255a15123c7SMark Brown }
256a15123c7SMark Brown 
arizona_spi_remove(struct spi_device * spi)257a0386bbaSUwe Kleine-König static void arizona_spi_remove(struct spi_device *spi)
258a15123c7SMark Brown {
259e9642d5eSJingoo Han 	struct arizona *arizona = spi_get_drvdata(spi);
2606f467e5fSWill Sheppard 
261a15123c7SMark Brown 	arizona_dev_exit(arizona);
262a15123c7SMark Brown }
263a15123c7SMark Brown 
264a15123c7SMark Brown static const struct spi_device_id arizona_spi_ids[] = {
265a15123c7SMark Brown 	{ "wm5102", WM5102 },
266e102befeSMark Brown 	{ "wm5110", WM5110 },
267e5d4ef0dSRichard Fitzgerald 	{ "wm8280", WM8280 },
268ea1f3339SRichard Fitzgerald 	{ "wm1831", WM1831 },
269ea1f3339SRichard Fitzgerald 	{ "cs47l24", CS47L24 },
270a15123c7SMark Brown 	{ },
271a15123c7SMark Brown };
272a15123c7SMark Brown MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
273a15123c7SMark Brown 
2743f65555cSCharles Keepax #ifdef CONFIG_OF
27510377bb2SCharles Keepax static const struct of_device_id arizona_spi_of_match[] = {
2763f65555cSCharles Keepax 	{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
2773f65555cSCharles Keepax 	{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
2783f65555cSCharles Keepax 	{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
2793f65555cSCharles Keepax 	{ .compatible = "wlf,wm1831", .data = (void *)WM1831 },
2803f65555cSCharles Keepax 	{ .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 },
2813f65555cSCharles Keepax 	{},
2823f65555cSCharles Keepax };
283972c91fdSCharles Keepax MODULE_DEVICE_TABLE(of, arizona_spi_of_match);
2843f65555cSCharles Keepax #endif
2853f65555cSCharles Keepax 
286a15123c7SMark Brown static struct spi_driver arizona_spi_driver = {
287a15123c7SMark Brown 	.driver = {
288a15123c7SMark Brown 		.name	= "arizona",
28950d3ac7dSPaul Cercueil 		.pm	= pm_ptr(&arizona_pm_ops),
2903f65555cSCharles Keepax 		.of_match_table	= of_match_ptr(arizona_spi_of_match),
291e9338367SHans de Goede 		.acpi_match_table = ACPI_PTR(arizona_acpi_match),
292a15123c7SMark Brown 	},
293a15123c7SMark Brown 	.probe		= arizona_spi_probe,
29484449216SBill Pemberton 	.remove		= arizona_spi_remove,
295a15123c7SMark Brown 	.id_table	= arizona_spi_ids,
296a15123c7SMark Brown };
297a15123c7SMark Brown 
298a15123c7SMark Brown module_spi_driver(arizona_spi_driver);
299a15123c7SMark Brown 
30006e577b4SHans de Goede MODULE_SOFTDEP("pre: arizona_ldo1");
301a15123c7SMark Brown MODULE_DESCRIPTION("Arizona SPI bus interface");
302a15123c7SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
303a15123c7SMark Brown MODULE_LICENSE("GPL");
304