1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * arizona-spi.c -- Arizona SPI bus interface 4 * 5 * Copyright 2012 Wolfson Microelectronics plc 6 * 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_ACPI 28 const struct acpi_gpio_params reset_gpios = { 1, 0, false }; 29 const struct acpi_gpio_params ldoena_gpios = { 2, 0, false }; 30 31 static 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 do 39 * not provide mappings for the GPIO-s coming from the Arizona codec itself. 40 */ 41 static 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 46 /* 47 * The AOSP 3.5 mm Headset: Accessory Specification gives the following values: 48 * Function A Play/Pause: 0 ohm 49 * Function D Voice assistant: 135 ohm 50 * Function B Volume Up 240 ohm 51 * Function C Volume Down 470 ohm 52 * Minimum Mic DC resistance 1000 ohm 53 * Minimum Ear speaker impedance 16 ohm 54 * Note the first max value below must be less then the min. speaker impedance, 55 * to allow CTIA/OMTP detection to work. The other max values are the closest 56 * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances. 57 */ 58 static const struct arizona_micd_range arizona_micd_aosp_ranges[] = { 59 { .max = 11, .key = KEY_PLAYPAUSE }, 60 { .max = 186, .key = KEY_VOICECOMMAND }, 61 { .max = 348, .key = KEY_VOLUMEUP }, 62 { .max = 752, .key = KEY_VOLUMEDOWN }, 63 }; 64 65 static void arizona_spi_acpi_remove_lookup(void *lookup) 66 { 67 gpiod_remove_lookup_table(lookup); 68 } 69 70 static int arizona_spi_acpi_probe(struct arizona *arizona) 71 { 72 struct gpiod_lookup_table *lookup; 73 acpi_status status; 74 int ret; 75 76 /* Add mappings for the 2 ACPI declared GPIOs used for reset and ldo-ena */ 77 devm_acpi_dev_add_driver_gpios(arizona->dev, arizona_acpi_gpios); 78 79 /* Add lookups for the SoCs own GPIOs used for micdet-polarity and spkVDD-enable */ 80 lookup = devm_kzalloc(arizona->dev, 81 struct_size(lookup, table, ARRAY_SIZE(arizona_soc_gpios) + 1), 82 GFP_KERNEL); 83 if (!lookup) 84 return -ENOMEM; 85 86 lookup->dev_id = dev_name(arizona->dev); 87 memcpy(lookup->table, arizona_soc_gpios, sizeof(arizona_soc_gpios)); 88 89 gpiod_add_lookup_table(lookup); 90 ret = devm_add_action_or_reset(arizona->dev, arizona_spi_acpi_remove_lookup, lookup); 91 if (ret) 92 return ret; 93 94 /* Enable 32KHz clock from SoC to codec for jack-detect */ 95 status = acpi_evaluate_object(ACPI_HANDLE(arizona->dev), "CLKE", NULL, NULL); 96 if (ACPI_FAILURE(status)) 97 dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status); 98 99 /* 100 * Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING 101 * The IRQ line will stay low when a new IRQ event happens between reading 102 * the IRQ status flags and acknowledging them. When the IRQ line stays 103 * low like this the IRQ will never trigger again when its type is set 104 * to IRQF_TRIGGER_FALLING. Correct the IRQ trigger-type to fix this. 105 * 106 * Note theoretically it is possible that some boards are not capable 107 * of handling active low level interrupts. In that case setting the 108 * flag to IRQF_TRIGGER_FALLING would not be a bug (and we would need 109 * to work around this) but so far all known usages of IRQF_TRIGGER_FALLING 110 * are a bug in the board's DSDT. 111 */ 112 arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; 113 114 /* Wait 200 ms after jack insertion */ 115 arizona->pdata.micd_detect_debounce = 200; 116 117 /* Use standard AOSP values for headset-button mappings */ 118 arizona->pdata.micd_ranges = arizona_micd_aosp_ranges; 119 arizona->pdata.num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges); 120 121 return 0; 122 } 123 124 static const struct acpi_device_id arizona_acpi_match[] = { 125 { 126 .id = "WM510204", 127 .driver_data = WM5102, 128 }, 129 { 130 .id = "WM510205", 131 .driver_data = WM5102, 132 }, 133 { } 134 }; 135 MODULE_DEVICE_TABLE(acpi, arizona_acpi_match); 136 #else 137 static int arizona_spi_acpi_probe(struct arizona *arizona) 138 { 139 return -ENODEV; 140 } 141 #endif 142 143 static int arizona_spi_probe(struct spi_device *spi) 144 { 145 const struct spi_device_id *id = spi_get_device_id(spi); 146 const void *match_data; 147 struct arizona *arizona; 148 const struct regmap_config *regmap_config = NULL; 149 unsigned long type = 0; 150 int ret; 151 152 match_data = device_get_match_data(&spi->dev); 153 if (match_data) 154 type = (unsigned long)match_data; 155 else if (id) 156 type = id->driver_data; 157 158 switch (type) { 159 case WM5102: 160 if (IS_ENABLED(CONFIG_MFD_WM5102)) 161 regmap_config = &wm5102_spi_regmap; 162 break; 163 case WM5110: 164 case WM8280: 165 if (IS_ENABLED(CONFIG_MFD_WM5110)) 166 regmap_config = &wm5110_spi_regmap; 167 break; 168 case WM1831: 169 case CS47L24: 170 if (IS_ENABLED(CONFIG_MFD_CS47L24)) 171 regmap_config = &cs47l24_spi_regmap; 172 break; 173 default: 174 dev_err(&spi->dev, "Unknown device type %ld\n", type); 175 return -EINVAL; 176 } 177 178 if (!regmap_config) { 179 dev_err(&spi->dev, 180 "No kernel support for device type %ld\n", type); 181 return -EINVAL; 182 } 183 184 arizona = devm_kzalloc(&spi->dev, sizeof(*arizona), GFP_KERNEL); 185 if (arizona == NULL) 186 return -ENOMEM; 187 188 arizona->regmap = devm_regmap_init_spi(spi, regmap_config); 189 if (IS_ERR(arizona->regmap)) { 190 ret = PTR_ERR(arizona->regmap); 191 dev_err(&spi->dev, "Failed to allocate register map: %d\n", 192 ret); 193 return ret; 194 } 195 196 arizona->type = type; 197 arizona->dev = &spi->dev; 198 arizona->irq = spi->irq; 199 200 if (has_acpi_companion(&spi->dev)) { 201 ret = arizona_spi_acpi_probe(arizona); 202 if (ret) 203 return ret; 204 } 205 206 return arizona_dev_init(arizona); 207 } 208 209 static int arizona_spi_remove(struct spi_device *spi) 210 { 211 struct arizona *arizona = spi_get_drvdata(spi); 212 213 arizona_dev_exit(arizona); 214 215 return 0; 216 } 217 218 static const struct spi_device_id arizona_spi_ids[] = { 219 { "wm5102", WM5102 }, 220 { "wm5110", WM5110 }, 221 { "wm8280", WM8280 }, 222 { "wm1831", WM1831 }, 223 { "cs47l24", CS47L24 }, 224 { }, 225 }; 226 MODULE_DEVICE_TABLE(spi, arizona_spi_ids); 227 228 static struct spi_driver arizona_spi_driver = { 229 .driver = { 230 .name = "arizona", 231 .pm = &arizona_pm_ops, 232 .of_match_table = of_match_ptr(arizona_of_match), 233 .acpi_match_table = ACPI_PTR(arizona_acpi_match), 234 }, 235 .probe = arizona_spi_probe, 236 .remove = arizona_spi_remove, 237 .id_table = arizona_spi_ids, 238 }; 239 240 module_spi_driver(arizona_spi_driver); 241 242 MODULE_SOFTDEP("pre: arizona_ldo1"); 243 MODULE_DESCRIPTION("Arizona SPI bus interface"); 244 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 245 MODULE_LICENSE("GPL"); 246