brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · eaa2b2b Raw
297 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * arizona-spi.c  --  Arizona SPI bus interface4 *5 * Copyright 2012 Wolfson Microelectronics plc6 *7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>8 */9 10#include <linux/acpi.h>11#include <linux/err.h>12#include <linux/gpio/consumer.h>13#include <linux/gpio/machine.h>14#include <linux/module.h>15#include <linux/pm_runtime.h>16#include <linux/regmap.h>17#include <linux/regulator/consumer.h>18#include <linux/slab.h>19#include <linux/spi/spi.h>20#include <linux/of.h>21#include <uapi/linux/input-event-codes.h>22 23#include <linux/mfd/arizona/core.h>24 25#include "arizona.h"26 27#ifdef CONFIG_ACPI28static const struct acpi_gpio_params reset_gpios = { 1, 0, false };29static const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };30 31static const struct acpi_gpio_mapping arizona_acpi_gpios[] = {32	{ "reset-gpios", &reset_gpios, 1, },33	{ "wlf,ldoena-gpios", &ldoena_gpios, 1 },34	{ }35};36 37/*38 * The ACPI resources for the device only describe external GPIO-s. They do39 * not provide mappings for the GPIO-s coming from the Arizona codec itself.40 */41static const struct gpiod_lookup arizona_soc_gpios[] = {42	{ "arizona", 2, "wlf,spkvdd-ena", 0, GPIO_ACTIVE_HIGH },43	{ "arizona", 4, "wlf,micd-pol", 0, GPIO_ACTIVE_LOW },44};45 46static void arizona_spi_acpi_remove_lookup(void *lookup)47{48	gpiod_remove_lookup_table(lookup);49}50 51/* For ACPI tables from boards which ship with Windows as factory OS */52static int arizona_spi_acpi_windows_probe(struct arizona *arizona)53{54	struct gpiod_lookup_table *lookup;55	acpi_status status;56	int ret;57 58	/* Add mappings for the 2 ACPI declared GPIOs used for reset and ldo-ena */59	devm_acpi_dev_add_driver_gpios(arizona->dev, arizona_acpi_gpios);60 61	/* Add lookups for the SoCs own GPIOs used for micdet-polarity and spkVDD-enable */62	lookup = devm_kzalloc(arizona->dev,63			      struct_size(lookup, table, ARRAY_SIZE(arizona_soc_gpios) + 1),64			      GFP_KERNEL);65	if (!lookup)66		return -ENOMEM;67 68	lookup->dev_id = dev_name(arizona->dev);69	memcpy(lookup->table, arizona_soc_gpios, sizeof(arizona_soc_gpios));70 71	gpiod_add_lookup_table(lookup);72	ret = devm_add_action_or_reset(arizona->dev, arizona_spi_acpi_remove_lookup, lookup);73	if (ret)74		return ret;75 76	/* Enable 32KHz clock from SoC to codec for jack-detect */77	status = acpi_evaluate_object(ACPI_HANDLE(arizona->dev), "CLKE", NULL, NULL);78	if (ACPI_FAILURE(status))79		dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status);80 81	return 0;82}83 84/* For ACPI tables from boards which ship with Android as factory OS */85static int arizona_spi_acpi_android_probe(struct arizona *arizona)86{87	int ret;88 89	/*90	 * Get the reset GPIO, treating -ENOENT as -EPROBE_DEFER to wait for91	 * the x86-android-tablets module to register the board specific GPIO92	 * lookup table.93	 */94	arizona->pdata.reset = devm_gpiod_get(arizona->dev, "reset", GPIOD_OUT_LOW);95	if (IS_ERR(arizona->pdata.reset)) {96		ret = PTR_ERR(arizona->pdata.reset);97		if (ret == -ENOENT) {98			dev_info_once(arizona->dev,99				      "Deferring probe till GPIO lookup is registered\n");100			ret = -EPROBE_DEFER;101		}102		return dev_err_probe(arizona->dev, ret, "getting reset GPIO\n");103	}104 105	return 0;106}107 108/*109 * The AOSP 3.5 mm Headset: Accessory Specification gives the following values:110 * Function A Play/Pause:           0 ohm111 * Function D Voice assistant:    135 ohm112 * Function B Volume Up           240 ohm113 * Function C Volume Down         470 ohm114 * Minimum Mic DC resistance     1000 ohm115 * Minimum Ear speaker impedance   16 ohm116 * Note the first max value below must be less then the min. speaker impedance,117 * to allow CTIA/OMTP detection to work. The other max values are the closest118 * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.119 */120static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {121	{ .max =  11, .key = KEY_PLAYPAUSE },122	{ .max = 186, .key = KEY_VOICECOMMAND },123	{ .max = 348, .key = KEY_VOLUMEUP },124	{ .max = 752, .key = KEY_VOLUMEDOWN },125};126 127static int arizona_spi_acpi_probe(struct arizona *arizona)128{129	struct acpi_device *adev = ACPI_COMPANION(arizona->dev);130	int ret;131 132	if (acpi_dev_hid_uid_match(adev, "10WM5102", NULL))133		ret = arizona_spi_acpi_android_probe(arizona);134	else135		ret = arizona_spi_acpi_windows_probe(arizona);136 137	if (ret)138		return ret;139 140	/*141	 * Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING142	 * The IRQ line will stay low when a new IRQ event happens between reading143	 * the IRQ status flags and acknowledging them. When the IRQ line stays144	 * low like this the IRQ will never trigger again when its type is set145	 * to IRQF_TRIGGER_FALLING. Correct the IRQ trigger-type to fix this.146	 *147	 * Note theoretically it is possible that some boards are not capable148	 * of handling active low level interrupts. In that case setting the149	 * flag to IRQF_TRIGGER_FALLING would not be a bug (and we would need150	 * to work around this) but so far all known usages of IRQF_TRIGGER_FALLING151	 * are a bug in the board's DSDT.152	 */153	arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;154 155	/* Wait 200 ms after jack insertion */156	arizona->pdata.micd_detect_debounce = 200;157 158	/* Use standard AOSP values for headset-button mappings */159	arizona->pdata.micd_ranges = arizona_micd_aosp_ranges;160	arizona->pdata.num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges);161 162	/* Use left headphone speaker for HP vs line-out detection */163	arizona->pdata.hpdet_channel = ARIZONA_ACCDET_MODE_HPL;164 165	return 0;166}167 168static const struct acpi_device_id arizona_acpi_match[] = {169	{170		.id = "WM510204",171		.driver_data = WM5102,172	},173	{174		.id = "WM510205",175		.driver_data = WM5102,176	},177	{178		.id = "10WM5102",179		.driver_data = WM5102,180	},181	{ }182};183MODULE_DEVICE_TABLE(acpi, arizona_acpi_match);184#else185static int arizona_spi_acpi_probe(struct arizona *arizona)186{187	return -ENODEV;188}189#endif190 191static int arizona_spi_probe(struct spi_device *spi)192{193	struct arizona *arizona;194	const struct regmap_config *regmap_config = NULL;195	unsigned long type = 0;196	int ret;197 198	type = (unsigned long)spi_get_device_match_data(spi);199	switch (type) {200	case WM5102:201		if (IS_ENABLED(CONFIG_MFD_WM5102))202			regmap_config = &wm5102_spi_regmap;203		break;204	case WM5110:205	case WM8280:206		if (IS_ENABLED(CONFIG_MFD_WM5110))207			regmap_config = &wm5110_spi_regmap;208		break;209	case WM1831:210	case CS47L24:211		if (IS_ENABLED(CONFIG_MFD_CS47L24))212			regmap_config = &cs47l24_spi_regmap;213		break;214	default:215		dev_err(&spi->dev, "Unknown device type %ld\n", type);216		return -EINVAL;217	}218 219	if (!regmap_config) {220		dev_err(&spi->dev,221			"No kernel support for device type %ld\n", type);222		return -EINVAL;223	}224 225	arizona = devm_kzalloc(&spi->dev, sizeof(*arizona), GFP_KERNEL);226	if (arizona == NULL)227		return -ENOMEM;228 229	arizona->regmap = devm_regmap_init_spi(spi, regmap_config);230	if (IS_ERR(arizona->regmap)) {231		ret = PTR_ERR(arizona->regmap);232		dev_err(&spi->dev, "Failed to allocate register map: %d\n",233			ret);234		return ret;235	}236 237	arizona->type = type;238	arizona->dev = &spi->dev;239	arizona->irq = spi->irq;240 241	if (has_acpi_companion(&spi->dev)) {242		ret = arizona_spi_acpi_probe(arizona);243		if (ret)244			return ret;245	}246 247	return arizona_dev_init(arizona);248}249 250static void arizona_spi_remove(struct spi_device *spi)251{252	struct arizona *arizona = spi_get_drvdata(spi);253 254	arizona_dev_exit(arizona);255}256 257static const struct spi_device_id arizona_spi_ids[] = {258	{ "wm5102", WM5102 },259	{ "wm5110", WM5110 },260	{ "wm8280", WM8280 },261	{ "wm1831", WM1831 },262	{ "cs47l24", CS47L24 },263	{ },264};265MODULE_DEVICE_TABLE(spi, arizona_spi_ids);266 267#ifdef CONFIG_OF268static const struct of_device_id arizona_spi_of_match[] = {269	{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },270	{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },271	{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },272	{ .compatible = "wlf,wm1831", .data = (void *)WM1831 },273	{ .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 },274	{},275};276MODULE_DEVICE_TABLE(of, arizona_spi_of_match);277#endif278 279static struct spi_driver arizona_spi_driver = {280	.driver = {281		.name	= "arizona",282		.pm	= pm_ptr(&arizona_pm_ops),283		.of_match_table	= of_match_ptr(arizona_spi_of_match),284		.acpi_match_table = ACPI_PTR(arizona_acpi_match),285	},286	.probe		= arizona_spi_probe,287	.remove		= arizona_spi_remove,288	.id_table	= arizona_spi_ids,289};290 291module_spi_driver(arizona_spi_driver);292 293MODULE_SOFTDEP("pre: arizona_ldo1");294MODULE_DESCRIPTION("Arizona SPI bus interface");295MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");296MODULE_LICENSE("GPL");297