| .. | .. |
|---|
| 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); |
|---|