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