.. | .. |
---|
19 | 19 | * |
---|
20 | 20 | */ |
---|
21 | 21 | |
---|
| 22 | +#include <linux/extcon-provider.h> |
---|
| 23 | +#include <linux/gpio.h> |
---|
| 24 | +#include <linux/iio/consumer.h> |
---|
| 25 | +#include <linux/iio/iio.h> |
---|
| 26 | +#include <linux/input.h> |
---|
| 27 | +#include <linux/interrupt.h> |
---|
| 28 | +#include <linux/irq.h> |
---|
22 | 29 | #include <linux/module.h> |
---|
| 30 | +#include <linux/of_gpio.h> |
---|
23 | 31 | #include <linux/platform_device.h> |
---|
24 | 32 | #include <linux/slab.h> |
---|
| 33 | +#include <linux/workqueue.h> |
---|
25 | 34 | #include <sound/core.h> |
---|
26 | 35 | #include <sound/jack.h> |
---|
27 | 36 | #include <sound/pcm.h> |
---|
.. | .. |
---|
29 | 38 | #include <sound/soc.h> |
---|
30 | 39 | #include <sound/soc-dapm.h> |
---|
31 | 40 | |
---|
32 | | -#include "../codecs/rk3308_codec_provider.h" |
---|
33 | | - |
---|
34 | 41 | #define DRV_NAME "rk-multicodecs" |
---|
35 | | -#define MAX_CODECS 2 |
---|
36 | 42 | #define WAIT_CARDS (SNDRV_CARDS - 1) |
---|
37 | 43 | #define DEFAULT_MCLK_FS 256 |
---|
| 44 | + |
---|
| 45 | +struct adc_keys_button { |
---|
| 46 | + u32 voltage; |
---|
| 47 | + u32 keycode; |
---|
| 48 | +}; |
---|
| 49 | + |
---|
| 50 | +struct input_dev_poller { |
---|
| 51 | + void (*poll)(struct input_dev *dev); |
---|
| 52 | + |
---|
| 53 | + unsigned int poll_interval_ms; |
---|
| 54 | + struct input_dev *input; |
---|
| 55 | + struct delayed_work work; |
---|
| 56 | +}; |
---|
38 | 57 | |
---|
39 | 58 | struct multicodecs_data { |
---|
40 | 59 | struct snd_soc_card snd_card; |
---|
41 | 60 | struct snd_soc_dai_link dai_link; |
---|
| 61 | + struct snd_soc_jack *jack_headset; |
---|
| 62 | + struct gpio_desc *hp_ctl_gpio; |
---|
| 63 | + struct gpio_desc *spk_ctl_gpio; |
---|
| 64 | + struct gpio_desc *hp_det_gpio; |
---|
| 65 | + struct iio_channel *adc; |
---|
| 66 | + struct extcon_dev *extcon; |
---|
| 67 | + struct delayed_work handler; |
---|
42 | 68 | unsigned int mclk_fs; |
---|
43 | 69 | bool codec_hp_det; |
---|
| 70 | + u32 num_keys; |
---|
| 71 | + u32 last_key; |
---|
| 72 | + u32 keyup_voltage; |
---|
| 73 | + const struct adc_keys_button *map; |
---|
| 74 | + struct input_dev *input; |
---|
| 75 | + struct input_dev_poller *poller; |
---|
44 | 76 | }; |
---|
45 | 77 | |
---|
46 | | -static struct snd_soc_jack mc_hp_jack; |
---|
| 78 | +static const unsigned int headset_extcon_cable[] = { |
---|
| 79 | + EXTCON_JACK_MICROPHONE, |
---|
| 80 | + EXTCON_JACK_HEADPHONE, |
---|
| 81 | + EXTCON_NONE, |
---|
| 82 | +}; |
---|
| 83 | + |
---|
| 84 | +static void mc_set_poll_interval(struct input_dev_poller *poller, unsigned int interval) |
---|
| 85 | +{ |
---|
| 86 | + if (poller) |
---|
| 87 | + poller->poll_interval_ms = interval; |
---|
| 88 | +} |
---|
| 89 | + |
---|
| 90 | +static void mc_keys_poller_queue_work(struct input_dev_poller *poller) |
---|
| 91 | +{ |
---|
| 92 | + unsigned long delay; |
---|
| 93 | + |
---|
| 94 | + delay = msecs_to_jiffies(poller->poll_interval_ms); |
---|
| 95 | + if (delay >= HZ) |
---|
| 96 | + delay = round_jiffies_relative(delay); |
---|
| 97 | + |
---|
| 98 | + queue_delayed_work(system_freezable_wq, &poller->work, delay); |
---|
| 99 | +} |
---|
| 100 | + |
---|
| 101 | +static void mc_keys_poller_work(struct work_struct *work) |
---|
| 102 | +{ |
---|
| 103 | + struct input_dev_poller *poller = |
---|
| 104 | + container_of(work, struct input_dev_poller, work.work); |
---|
| 105 | + |
---|
| 106 | + poller->poll(poller->input); |
---|
| 107 | + mc_keys_poller_queue_work(poller); |
---|
| 108 | +} |
---|
| 109 | + |
---|
| 110 | +static void mc_keys_poller_start(struct input_dev_poller *poller) |
---|
| 111 | +{ |
---|
| 112 | + if (poller->poll_interval_ms > 0) { |
---|
| 113 | + poller->poll(poller->input); |
---|
| 114 | + mc_keys_poller_queue_work(poller); |
---|
| 115 | + } |
---|
| 116 | +} |
---|
| 117 | + |
---|
| 118 | +static void mc_keys_poller_stop(struct input_dev_poller *poller) |
---|
| 119 | +{ |
---|
| 120 | + cancel_delayed_work_sync(&poller->work); |
---|
| 121 | +} |
---|
| 122 | + |
---|
| 123 | +static int mc_keys_setup_polling(struct multicodecs_data *mc_data, |
---|
| 124 | + void (*poll_fn)(struct input_dev *dev)) |
---|
| 125 | +{ |
---|
| 126 | + struct input_dev_poller *poller; |
---|
| 127 | + |
---|
| 128 | + poller = devm_kzalloc(mc_data->snd_card.dev, sizeof(*poller), GFP_KERNEL); |
---|
| 129 | + if (!poller) |
---|
| 130 | + return -ENOMEM; |
---|
| 131 | + |
---|
| 132 | + INIT_DELAYED_WORK(&poller->work, mc_keys_poller_work); |
---|
| 133 | + poller->input = mc_data->input; |
---|
| 134 | + poller->poll = poll_fn; |
---|
| 135 | + mc_data->poller = poller; |
---|
| 136 | + |
---|
| 137 | + return 0; |
---|
| 138 | +} |
---|
| 139 | + |
---|
| 140 | +static void mc_keys_poll(struct input_dev *input) |
---|
| 141 | +{ |
---|
| 142 | + struct multicodecs_data *mc_data = input_get_drvdata(input); |
---|
| 143 | + int i, value, ret; |
---|
| 144 | + u32 diff, closest = 0xffffffff; |
---|
| 145 | + int keycode = 0; |
---|
| 146 | + |
---|
| 147 | + ret = iio_read_channel_processed(mc_data->adc, &value); |
---|
| 148 | + if (unlikely(ret < 0)) { |
---|
| 149 | + /* Forcibly release key if any was pressed */ |
---|
| 150 | + value = mc_data->keyup_voltage; |
---|
| 151 | + } else { |
---|
| 152 | + for (i = 0; i < mc_data->num_keys; i++) { |
---|
| 153 | + diff = abs(mc_data->map[i].voltage - value); |
---|
| 154 | + if (diff < closest) { |
---|
| 155 | + closest = diff; |
---|
| 156 | + keycode = mc_data->map[i].keycode; |
---|
| 157 | + } |
---|
| 158 | + } |
---|
| 159 | + } |
---|
| 160 | + |
---|
| 161 | + if (abs(mc_data->keyup_voltage - value) < closest) |
---|
| 162 | + keycode = 0; |
---|
| 163 | + |
---|
| 164 | + if (mc_data->last_key && mc_data->last_key != keycode) |
---|
| 165 | + input_report_key(input, mc_data->last_key, 0); |
---|
| 166 | + |
---|
| 167 | + if (keycode) |
---|
| 168 | + input_report_key(input, keycode, 1); |
---|
| 169 | + |
---|
| 170 | + input_sync(input); |
---|
| 171 | + mc_data->last_key = keycode; |
---|
| 172 | +} |
---|
| 173 | + |
---|
| 174 | +static int mc_keys_load_keymap(struct device *dev, |
---|
| 175 | + struct multicodecs_data *mc_data) |
---|
| 176 | +{ |
---|
| 177 | + struct adc_keys_button *map; |
---|
| 178 | + struct fwnode_handle *child; |
---|
| 179 | + int i = 0; |
---|
| 180 | + |
---|
| 181 | + mc_data->num_keys = device_get_child_node_count(dev); |
---|
| 182 | + if (mc_data->num_keys == 0) { |
---|
| 183 | + dev_err(dev, "keymap is missing\n"); |
---|
| 184 | + return -EINVAL; |
---|
| 185 | + } |
---|
| 186 | + |
---|
| 187 | + map = devm_kmalloc_array(dev, mc_data->num_keys, sizeof(*map), GFP_KERNEL); |
---|
| 188 | + if (!map) |
---|
| 189 | + return -ENOMEM; |
---|
| 190 | + |
---|
| 191 | + device_for_each_child_node(dev, child) { |
---|
| 192 | + if (fwnode_property_read_u32(child, "press-threshold-microvolt", |
---|
| 193 | + &map[i].voltage)) { |
---|
| 194 | + dev_err(dev, "Key with invalid or missing voltage\n"); |
---|
| 195 | + fwnode_handle_put(child); |
---|
| 196 | + return -EINVAL; |
---|
| 197 | + } |
---|
| 198 | + map[i].voltage /= 1000; |
---|
| 199 | + |
---|
| 200 | + if (fwnode_property_read_u32(child, "linux,code", |
---|
| 201 | + &map[i].keycode)) { |
---|
| 202 | + dev_err(dev, "Key with invalid or missing linux,code\n"); |
---|
| 203 | + fwnode_handle_put(child); |
---|
| 204 | + return -EINVAL; |
---|
| 205 | + } |
---|
| 206 | + |
---|
| 207 | + i++; |
---|
| 208 | + } |
---|
| 209 | + mc_data->map = map; |
---|
| 210 | + return 0; |
---|
| 211 | +} |
---|
| 212 | + |
---|
| 213 | +static void adc_jack_handler(struct work_struct *work) |
---|
| 214 | +{ |
---|
| 215 | + struct multicodecs_data *mc_data = container_of(to_delayed_work(work), |
---|
| 216 | + struct multicodecs_data, |
---|
| 217 | + handler); |
---|
| 218 | + struct snd_soc_jack *jack_headset = mc_data->jack_headset; |
---|
| 219 | + int adc, ret = 0; |
---|
| 220 | + |
---|
| 221 | + if (!gpiod_get_value(mc_data->hp_det_gpio)) { |
---|
| 222 | + snd_soc_jack_report(jack_headset, 0, SND_JACK_HEADSET); |
---|
| 223 | + extcon_set_state_sync(mc_data->extcon, |
---|
| 224 | + EXTCON_JACK_HEADPHONE, false); |
---|
| 225 | + extcon_set_state_sync(mc_data->extcon, |
---|
| 226 | + EXTCON_JACK_MICROPHONE, false); |
---|
| 227 | + if (mc_data->poller) |
---|
| 228 | + mc_keys_poller_stop(mc_data->poller); |
---|
| 229 | + |
---|
| 230 | + return; |
---|
| 231 | + } |
---|
| 232 | + if (!mc_data->adc) { |
---|
| 233 | + /* no ADC, so is headphone */ |
---|
| 234 | + snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET); |
---|
| 235 | + extcon_set_state_sync(mc_data->extcon, EXTCON_JACK_HEADPHONE, true); |
---|
| 236 | + extcon_set_state_sync(mc_data->extcon, EXTCON_JACK_MICROPHONE, false); |
---|
| 237 | + return; |
---|
| 238 | + } |
---|
| 239 | + ret = iio_read_channel_processed(mc_data->adc, &adc); |
---|
| 240 | + if (ret < 0) { |
---|
| 241 | + /* failed to read ADC, so assume headphone */ |
---|
| 242 | + snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET); |
---|
| 243 | + extcon_set_state_sync(mc_data->extcon, EXTCON_JACK_HEADPHONE, true); |
---|
| 244 | + extcon_set_state_sync(mc_data->extcon, EXTCON_JACK_MICROPHONE, false); |
---|
| 245 | + |
---|
| 246 | + } else { |
---|
| 247 | + snd_soc_jack_report(jack_headset, |
---|
| 248 | + snd_soc_jack_get_type(jack_headset, adc), |
---|
| 249 | + SND_JACK_HEADSET); |
---|
| 250 | + extcon_set_state_sync(mc_data->extcon, EXTCON_JACK_HEADPHONE, true); |
---|
| 251 | + |
---|
| 252 | + if (snd_soc_jack_get_type(jack_headset, adc) == SND_JACK_HEADSET) { |
---|
| 253 | + extcon_set_state_sync(mc_data->extcon, EXTCON_JACK_MICROPHONE, true); |
---|
| 254 | + if (mc_data->poller) |
---|
| 255 | + mc_keys_poller_start(mc_data->poller); |
---|
| 256 | + } |
---|
| 257 | + } |
---|
| 258 | +}; |
---|
| 259 | + |
---|
| 260 | +static irqreturn_t headset_det_irq_thread(int irq, void *data) |
---|
| 261 | +{ |
---|
| 262 | + struct multicodecs_data *mc_data = (struct multicodecs_data *)data; |
---|
| 263 | + |
---|
| 264 | + queue_delayed_work(system_power_efficient_wq, &mc_data->handler, msecs_to_jiffies(200)); |
---|
| 265 | + |
---|
| 266 | + return IRQ_HANDLED; |
---|
| 267 | +}; |
---|
| 268 | + |
---|
| 269 | +static int mc_hp_event(struct snd_soc_dapm_widget *w, |
---|
| 270 | + struct snd_kcontrol *kcontrol, int event) |
---|
| 271 | +{ |
---|
| 272 | + struct snd_soc_card *card = w->dapm->card; |
---|
| 273 | + struct multicodecs_data *mc_data = snd_soc_card_get_drvdata(card); |
---|
| 274 | + |
---|
| 275 | + switch (event) { |
---|
| 276 | + case SND_SOC_DAPM_POST_PMU: |
---|
| 277 | + gpiod_set_value_cansleep(mc_data->hp_ctl_gpio, 1); |
---|
| 278 | + break; |
---|
| 279 | + case SND_SOC_DAPM_PRE_PMD: |
---|
| 280 | + gpiod_set_value_cansleep(mc_data->hp_ctl_gpio, 0); |
---|
| 281 | + break; |
---|
| 282 | + default: |
---|
| 283 | + return 0; |
---|
| 284 | + |
---|
| 285 | + } |
---|
| 286 | + |
---|
| 287 | + return 0; |
---|
| 288 | +} |
---|
| 289 | + |
---|
| 290 | +static int mc_spk_event(struct snd_soc_dapm_widget *w, |
---|
| 291 | + struct snd_kcontrol *kcontrol, int event) |
---|
| 292 | +{ |
---|
| 293 | + struct snd_soc_card *card = w->dapm->card; |
---|
| 294 | + struct multicodecs_data *mc_data = snd_soc_card_get_drvdata(card); |
---|
| 295 | + |
---|
| 296 | + switch (event) { |
---|
| 297 | + case SND_SOC_DAPM_POST_PMU: |
---|
| 298 | + gpiod_set_value_cansleep(mc_data->spk_ctl_gpio, 1); |
---|
| 299 | + break; |
---|
| 300 | + case SND_SOC_DAPM_PRE_PMD: |
---|
| 301 | + gpiod_set_value_cansleep(mc_data->spk_ctl_gpio, 0); |
---|
| 302 | + break; |
---|
| 303 | + default: |
---|
| 304 | + return 0; |
---|
| 305 | + |
---|
| 306 | + } |
---|
| 307 | + |
---|
| 308 | + return 0; |
---|
| 309 | +} |
---|
| 310 | + |
---|
| 311 | +static const struct snd_soc_dapm_widget mc_dapm_widgets[] = { |
---|
| 312 | + |
---|
| 313 | + SND_SOC_DAPM_HP("Headphone", NULL), |
---|
| 314 | + SND_SOC_DAPM_SPK("Speaker", NULL), |
---|
| 315 | + SND_SOC_DAPM_MIC("Main Mic", NULL), |
---|
| 316 | + SND_SOC_DAPM_MIC("Headset Mic", NULL), |
---|
| 317 | + SND_SOC_DAPM_SUPPLY("Speaker Power", |
---|
| 318 | + SND_SOC_NOPM, 0, 0, |
---|
| 319 | + mc_spk_event, |
---|
| 320 | + SND_SOC_DAPM_POST_PMU | |
---|
| 321 | + SND_SOC_DAPM_PRE_PMD), |
---|
| 322 | + SND_SOC_DAPM_SUPPLY("Headphone Power", |
---|
| 323 | + SND_SOC_NOPM, 0, 0, |
---|
| 324 | + mc_hp_event, |
---|
| 325 | + SND_SOC_DAPM_POST_PMU | |
---|
| 326 | + SND_SOC_DAPM_PRE_PMD), |
---|
| 327 | +}; |
---|
| 328 | + |
---|
| 329 | +static const struct snd_kcontrol_new mc_controls[] = { |
---|
| 330 | + SOC_DAPM_PIN_SWITCH("Headphone"), |
---|
| 331 | + SOC_DAPM_PIN_SWITCH("Speaker"), |
---|
| 332 | + SOC_DAPM_PIN_SWITCH("Main Mic"), |
---|
| 333 | + SOC_DAPM_PIN_SWITCH("Headset Mic"), |
---|
| 334 | +}; |
---|
47 | 335 | |
---|
48 | 336 | static int rk_multicodecs_hw_params(struct snd_pcm_substream *substream, |
---|
49 | 337 | struct snd_pcm_hw_params *params) |
---|
50 | 338 | { |
---|
51 | 339 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
52 | | - struct snd_soc_dai *codec_dai = rtd->codec_dai; |
---|
53 | 340 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 341 | + struct snd_soc_dai *codec_dai; |
---|
54 | 342 | struct multicodecs_data *mc_data = snd_soc_card_get_drvdata(rtd->card); |
---|
55 | 343 | unsigned int mclk; |
---|
56 | | - int ret; |
---|
| 344 | + int ret, i; |
---|
57 | 345 | |
---|
58 | 346 | mclk = params_rate(params) * mc_data->mclk_fs; |
---|
59 | 347 | |
---|
60 | | - ret = snd_soc_dai_set_sysclk(codec_dai, substream->stream, mclk, |
---|
61 | | - SND_SOC_CLOCK_IN); |
---|
62 | | - if (ret && ret != -ENOTSUPP) { |
---|
63 | | - pr_err("Set codec_dai sysclk failed: %d\n", ret); |
---|
64 | | - goto out; |
---|
| 348 | + for (i = 0; i < rtd->num_codecs; i++) { |
---|
| 349 | + codec_dai = rtd->codec_dais[i]; |
---|
| 350 | + ret = snd_soc_dai_set_sysclk(codec_dai, substream->stream, mclk, |
---|
| 351 | + SND_SOC_CLOCK_IN); |
---|
| 352 | + if (ret && ret != -ENOTSUPP) { |
---|
| 353 | + pr_err("Set codec_dai sysclk failed: %d\n", ret); |
---|
| 354 | + goto out; |
---|
| 355 | + } |
---|
65 | 356 | } |
---|
66 | 357 | |
---|
67 | 358 | ret = snd_soc_dai_set_sysclk(cpu_dai, substream->stream, mclk, |
---|
.. | .. |
---|
80 | 371 | static int rk_dailink_init(struct snd_soc_pcm_runtime *rtd) |
---|
81 | 372 | { |
---|
82 | 373 | struct multicodecs_data *mc_data = snd_soc_card_get_drvdata(rtd->card); |
---|
| 374 | + struct snd_soc_card *card = rtd->card; |
---|
| 375 | + struct snd_soc_jack *jack_headset; |
---|
| 376 | + int ret, irq; |
---|
| 377 | + struct snd_soc_jack_pin *pins; |
---|
| 378 | + struct snd_soc_jack_zone *zones; |
---|
| 379 | + struct snd_soc_jack_pin jack_pins[] = { |
---|
| 380 | + { |
---|
| 381 | + .pin = "Headphone", |
---|
| 382 | + .mask = SND_JACK_HEADPHONE, |
---|
| 383 | + }, { |
---|
| 384 | + .pin = "Headset Mic", |
---|
| 385 | + .mask = SND_JACK_MICROPHONE, |
---|
| 386 | + }, |
---|
| 387 | + }; |
---|
| 388 | + struct snd_soc_jack_zone headset_zones[] = { |
---|
| 389 | + { |
---|
| 390 | + .min_mv = 0, |
---|
| 391 | + .max_mv = 222, |
---|
| 392 | + .jack_type = SND_JACK_HEADPHONE, |
---|
| 393 | + }, { |
---|
| 394 | + .min_mv = 223, |
---|
| 395 | + .max_mv = 1500, |
---|
| 396 | + .jack_type = SND_JACK_HEADSET, |
---|
| 397 | + }, { |
---|
| 398 | + .min_mv = 1501, |
---|
| 399 | + .max_mv = UINT_MAX, |
---|
| 400 | + .jack_type = SND_JACK_HEADPHONE, |
---|
| 401 | + } |
---|
| 402 | + }; |
---|
| 403 | + |
---|
| 404 | + if ((!mc_data->codec_hp_det) && (gpiod_to_irq(mc_data->hp_det_gpio) < 0)) { |
---|
| 405 | + dev_info(card->dev, "Don't need to map headset detect gpio to irq\n"); |
---|
| 406 | + return 0; |
---|
| 407 | + } |
---|
| 408 | + |
---|
| 409 | + jack_headset = devm_kzalloc(card->dev, sizeof(*jack_headset), GFP_KERNEL); |
---|
| 410 | + if (!jack_headset) |
---|
| 411 | + return -ENOMEM; |
---|
| 412 | + |
---|
| 413 | + pins = devm_kmemdup(card->dev, jack_pins, |
---|
| 414 | + sizeof(*jack_pins) * ARRAY_SIZE(jack_pins), GFP_KERNEL); |
---|
| 415 | + if (!pins) |
---|
| 416 | + return -ENOMEM; |
---|
| 417 | + |
---|
| 418 | + zones = devm_kmemdup(card->dev, headset_zones, |
---|
| 419 | + sizeof(*headset_zones) * ARRAY_SIZE(headset_zones), GFP_KERNEL); |
---|
| 420 | + if (!zones) |
---|
| 421 | + return -ENOMEM; |
---|
| 422 | + |
---|
| 423 | + ret = snd_soc_card_jack_new(card, "Headset", |
---|
| 424 | + SND_JACK_HEADSET, |
---|
| 425 | + jack_headset, |
---|
| 426 | + pins, ARRAY_SIZE(jack_pins)); |
---|
| 427 | + if (ret) |
---|
| 428 | + return ret; |
---|
| 429 | + ret = snd_soc_jack_add_zones(jack_headset, ARRAY_SIZE(headset_zones), zones); |
---|
| 430 | + if (ret) |
---|
| 431 | + return ret; |
---|
| 432 | + |
---|
| 433 | + mc_data->jack_headset = jack_headset; |
---|
83 | 434 | |
---|
84 | 435 | if (mc_data->codec_hp_det) { |
---|
85 | | - snd_soc_card_jack_new(rtd->card, "Headphones", |
---|
86 | | - SND_JACK_HEADPHONE, |
---|
87 | | - &mc_hp_jack, NULL, 0); |
---|
| 436 | + struct snd_soc_dai *codec_dai; |
---|
| 437 | + int i; |
---|
88 | 438 | |
---|
89 | | -#ifdef CONFIG_SND_SOC_RK3308 |
---|
90 | | - if (rk3308_codec_set_jack_detect_cb) |
---|
91 | | - rk3308_codec_set_jack_detect_cb(rtd->codec_dai->component, &mc_hp_jack); |
---|
92 | | -#endif |
---|
| 439 | + /* set jack for the first successful one */ |
---|
| 440 | + for (i = 0; i < rtd->num_codecs; i++) { |
---|
| 441 | + codec_dai = rtd->codec_dais[i]; |
---|
| 442 | + ret = snd_soc_component_set_jack(codec_dai->component, |
---|
| 443 | + jack_headset, NULL); |
---|
| 444 | + if (ret >= 0) |
---|
| 445 | + break; |
---|
| 446 | + } |
---|
| 447 | + } else { |
---|
| 448 | + irq = gpiod_to_irq(mc_data->hp_det_gpio); |
---|
| 449 | + if (irq >= 0) { |
---|
| 450 | + ret = devm_request_threaded_irq(card->dev, irq, NULL, |
---|
| 451 | + headset_det_irq_thread, |
---|
| 452 | + IRQF_TRIGGER_RISING | |
---|
| 453 | + IRQF_TRIGGER_FALLING | |
---|
| 454 | + IRQF_ONESHOT, |
---|
| 455 | + "headset_detect", |
---|
| 456 | + mc_data); |
---|
| 457 | + if (ret) { |
---|
| 458 | + dev_err(card->dev, "Failed to request headset detect irq"); |
---|
| 459 | + return ret; |
---|
| 460 | + } |
---|
| 461 | + |
---|
| 462 | + queue_delayed_work(system_power_efficient_wq, |
---|
| 463 | + &mc_data->handler, msecs_to_jiffies(50)); |
---|
| 464 | + } |
---|
93 | 465 | } |
---|
94 | 466 | |
---|
95 | 467 | return 0; |
---|
.. | .. |
---|
216 | 588 | struct multicodecs_data *mc_data; |
---|
217 | 589 | struct of_phandle_args args; |
---|
218 | 590 | struct device_node *node; |
---|
| 591 | + struct input_dev *input; |
---|
219 | 592 | u32 val; |
---|
220 | | - int count; |
---|
| 593 | + int count, value; |
---|
221 | 594 | int ret = 0, i = 0, idx = 0; |
---|
222 | 595 | const char *prefix = "rockchip,"; |
---|
223 | 596 | |
---|
.. | .. |
---|
244 | 617 | link->stream_name = link->name; |
---|
245 | 618 | link->init = rk_dailink_init; |
---|
246 | 619 | link->ops = &rk_ops; |
---|
| 620 | + link->ignore_pmdown_time = 1; |
---|
247 | 621 | |
---|
248 | 622 | card->dai_link = link; |
---|
249 | 623 | card->num_links = 1; |
---|
| 624 | + card->dapm_widgets = mc_dapm_widgets; |
---|
| 625 | + card->num_dapm_widgets = ARRAY_SIZE(mc_dapm_widgets); |
---|
| 626 | + card->controls = mc_controls; |
---|
| 627 | + card->num_controls = ARRAY_SIZE(mc_controls); |
---|
250 | 628 | card->num_aux_devs = 0; |
---|
251 | 629 | |
---|
252 | 630 | count = of_count_phandle_with_args(np, "rockchip,codec", NULL); |
---|
253 | | - if (count < 0 || count > MAX_CODECS) |
---|
| 631 | + if (count < 0) |
---|
254 | 632 | return -EINVAL; |
---|
255 | 633 | |
---|
256 | 634 | /* refine codecs, remove unavailable node */ |
---|
.. | .. |
---|
267 | 645 | |
---|
268 | 646 | codecs = devm_kcalloc(&pdev->dev, idx, |
---|
269 | 647 | sizeof(*codecs), GFP_KERNEL); |
---|
| 648 | + if (!codecs) |
---|
| 649 | + return -ENOMEM; |
---|
| 650 | + |
---|
270 | 651 | link->codecs = codecs; |
---|
271 | 652 | link->num_codecs = idx; |
---|
272 | 653 | idx = 0; |
---|
.. | .. |
---|
305 | 686 | mc_data->codec_hp_det = |
---|
306 | 687 | of_property_read_bool(np, "rockchip,codec-hp-det"); |
---|
307 | 688 | |
---|
| 689 | + mc_data->adc = devm_iio_channel_get(&pdev->dev, "adc-detect"); |
---|
| 690 | + |
---|
| 691 | + if (IS_ERR(mc_data->adc)) { |
---|
| 692 | + if (PTR_ERR(mc_data->adc) != -EPROBE_DEFER) { |
---|
| 693 | + mc_data->adc = NULL; |
---|
| 694 | + dev_warn(&pdev->dev, "Failed to get ADC channel"); |
---|
| 695 | + } |
---|
| 696 | + } else { |
---|
| 697 | + if (mc_data->adc->channel->type != IIO_VOLTAGE) |
---|
| 698 | + return -EINVAL; |
---|
| 699 | + |
---|
| 700 | + if (device_property_read_u32(&pdev->dev, "keyup-threshold-microvolt", |
---|
| 701 | + &mc_data->keyup_voltage)) { |
---|
| 702 | + dev_warn(&pdev->dev, "Invalid or missing keyup voltage\n"); |
---|
| 703 | + return -EINVAL; |
---|
| 704 | + } |
---|
| 705 | + mc_data->keyup_voltage /= 1000; |
---|
| 706 | + |
---|
| 707 | + ret = mc_keys_load_keymap(&pdev->dev, mc_data); |
---|
| 708 | + if (ret) |
---|
| 709 | + return ret; |
---|
| 710 | + |
---|
| 711 | + input = devm_input_allocate_device(&pdev->dev); |
---|
| 712 | + if (IS_ERR(input)) { |
---|
| 713 | + dev_err(&pdev->dev, "failed to allocate input device\n"); |
---|
| 714 | + return PTR_ERR(input); |
---|
| 715 | + } |
---|
| 716 | + |
---|
| 717 | + input_set_drvdata(input, mc_data); |
---|
| 718 | + |
---|
| 719 | + input->name = "headset-keys"; |
---|
| 720 | + input->phys = "headset-keys/input0"; |
---|
| 721 | + input->id.bustype = BUS_HOST; |
---|
| 722 | + input->id.vendor = 0x0001; |
---|
| 723 | + input->id.product = 0x0001; |
---|
| 724 | + input->id.version = 0x0100; |
---|
| 725 | + |
---|
| 726 | + __set_bit(EV_KEY, input->evbit); |
---|
| 727 | + for (i = 0; i < mc_data->num_keys; i++) |
---|
| 728 | + __set_bit(mc_data->map[i].keycode, input->keybit); |
---|
| 729 | + |
---|
| 730 | + if (device_property_read_bool(&pdev->dev, "autorepeat")) |
---|
| 731 | + __set_bit(EV_REP, input->evbit); |
---|
| 732 | + |
---|
| 733 | + mc_data->input = input; |
---|
| 734 | + ret = mc_keys_setup_polling(mc_data, mc_keys_poll); |
---|
| 735 | + if (ret) { |
---|
| 736 | + dev_err(&pdev->dev, "Unable to set up polling: %d\n", ret); |
---|
| 737 | + return ret; |
---|
| 738 | + } |
---|
| 739 | + |
---|
| 740 | + if (!device_property_read_u32(&pdev->dev, "poll-interval", &value)) |
---|
| 741 | + mc_set_poll_interval(mc_data->poller, value); |
---|
| 742 | + |
---|
| 743 | + ret = input_register_device(mc_data->input); |
---|
| 744 | + if (ret) { |
---|
| 745 | + dev_err(&pdev->dev, "Unable to register input device: %d\n", ret); |
---|
| 746 | + return ret; |
---|
| 747 | + } |
---|
| 748 | + } |
---|
| 749 | + |
---|
| 750 | + INIT_DEFERRABLE_WORK(&mc_data->handler, adc_jack_handler); |
---|
| 751 | + |
---|
| 752 | + mc_data->spk_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, |
---|
| 753 | + "spk-con", |
---|
| 754 | + GPIOD_OUT_LOW); |
---|
| 755 | + if (IS_ERR(mc_data->spk_ctl_gpio)) |
---|
| 756 | + return PTR_ERR(mc_data->spk_ctl_gpio); |
---|
| 757 | + |
---|
| 758 | + mc_data->hp_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, |
---|
| 759 | + "hp-con", |
---|
| 760 | + GPIOD_OUT_LOW); |
---|
| 761 | + if (IS_ERR(mc_data->hp_ctl_gpio)) |
---|
| 762 | + return PTR_ERR(mc_data->hp_ctl_gpio); |
---|
| 763 | + |
---|
| 764 | + mc_data->hp_det_gpio = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); |
---|
| 765 | + if (IS_ERR(mc_data->hp_det_gpio)) |
---|
| 766 | + return PTR_ERR(mc_data->hp_det_gpio); |
---|
| 767 | + |
---|
| 768 | + mc_data->extcon = devm_extcon_dev_allocate(&pdev->dev, headset_extcon_cable); |
---|
| 769 | + if (IS_ERR(mc_data->extcon)) { |
---|
| 770 | + dev_err(&pdev->dev, "allocate extcon failed\n"); |
---|
| 771 | + return PTR_ERR(mc_data->extcon); |
---|
| 772 | + } |
---|
| 773 | + |
---|
| 774 | + ret = devm_extcon_dev_register(&pdev->dev, mc_data->extcon); |
---|
| 775 | + if (ret) { |
---|
| 776 | + dev_err(&pdev->dev, "failed to register extcon: %d\n", ret); |
---|
| 777 | + return ret; |
---|
| 778 | + } |
---|
| 779 | + |
---|
| 780 | + ret = snd_soc_of_parse_audio_routing(card, "rockchip,audio-routing"); |
---|
| 781 | + if (ret < 0) |
---|
| 782 | + dev_warn(&pdev->dev, "Audio routing invalid/unspecified\n"); |
---|
| 783 | + |
---|
308 | 784 | snd_soc_card_set_drvdata(card, mc_data); |
---|
309 | 785 | |
---|
310 | 786 | ret = devm_snd_soc_register_card(&pdev->dev, card); |
---|