static int rk_multicodecs_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
struct device_node *np = pdev->dev.of_node;
struct snd_soc_dai_link *link;
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link_component *platforms;
struct snd_soc_dai_link_component *codecs;
struct multicodecs_data *mc_data;
struct of_phandle_args args;
struct device_node *node;
struct input_dev *input;
u32 val;
int count, value;
int ret = 0, i = 0, idx = 0;
const char *prefix = "rockchip,";
ret = wait_locked_card(np, &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "check_lock_card failed: %d\n", ret);
return ret;
}
mc_data = devm_kzalloc(&pdev->dev, sizeof(*mc_data), GFP_KERNEL);
if (!mc_data)
return -ENOMEM;
cpus = devm_kzalloc(&pdev->dev, sizeof(*cpus), GFP_KERNEL);
if (!cpus)
return -ENOMEM;
platforms = devm_kzalloc(&pdev->dev, sizeof(*platforms), GFP_KERNEL);
if (!platforms)
return -ENOMEM;
card = &mc_data->snd_card;
card->dev = &pdev->dev;
/* Parse the card name from DT */
ret = snd_soc_of_parse_card_name(card, "rockchip,card-name");
if (ret < 0)
return ret;
link = &mc_data->dai_link;
link->name = "dailink-multicodecs";
link->stream_name = link->name;
link->init = rk_dailink_init;
link->ops = &rk_ops;
link->cpus = cpus;
link->platforms = platforms;
link->num_cpus = 1;
link->num_platforms = 1;
link->ignore_pmdown_time = 1;
card->dai_link = link;
card->num_links = 1;
card->dapm_widgets = mc_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(mc_dapm_widgets);
card->controls = mc_controls;
card->num_controls = ARRAY_SIZE(mc_controls);
card->num_aux_devs = 0;
count = of_count_phandle_with_args(np, "rockchip,codec", NULL);
if (count < 0)
return -EINVAL;
/* refine codecs, remove unavailable node */
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "rockchip,codec", i);
if (!node)
return -ENODEV;
if (of_device_is_available(node))
idx++;
}
if (!idx)
return -ENODEV;
codecs = devm_kcalloc(&pdev->dev, idx,
sizeof(*codecs), GFP_KERNEL);
link->codecs = codecs;
link->num_codecs = idx;
idx = 0;
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "rockchip,codec", i);
if (!node)
return -ENODEV;
if (!of_device_is_available(node))
continue;
ret = of_parse_phandle_with_fixed_args(np, "rockchip,codec",
0, i, &args);
if (ret)
return ret;
codecs[idx].of_node = node;
ret = snd_soc_get_dai_name(&args, &codecs[idx].dai_name);
if (ret)
return ret;
idx++;
}
/* Only reference the codecs[0].of_node which maybe as master. */
rk_multicodecs_parse_daifmt(np, codecs[0].of_node, mc_data, prefix);
link->cpus->of_node = of_parse_phandle(np, "rockchip,cpu", 0);
if (!link->cpus->of_node)
return -ENODEV;
link->platforms->of_node = link->cpus->of_node;
mc_data->mclk_fs = DEFAULT_MCLK_FS;
if (!of_property_read_u32(np, "rockchip,mclk-fs", &val))
mc_data->mclk_fs = val;
mc_data->mclk_adapt = 0;
if (!of_property_read_u32(np, "rockchip,mclk-adapt", &val))
mc_data->mclk_adapt = val;
dev_err(&pdev->dev, "%s mclk_adapt=%d\n", __func__, mc_data->mclk_adapt);
mc_data->codec_hp_det =
of_property_read_bool(np, "rockchip,codec-hp-det");
mc_data->adc = devm_iio_channel_get(&pdev->dev, "adc-detect");
if (IS_ERR(mc_data->adc)) {
if (PTR_ERR(mc_data->adc) != -EPROBE_DEFER) {
mc_data->adc = NULL;
dev_warn(&pdev->dev, "Failed to get ADC channel");
}
} else {
if (mc_data->adc->channel->type != IIO_VOLTAGE)
return -EINVAL;
if (device_property_read_u32(&pdev->dev, "keyup-threshold-microvolt",
&mc_data->keyup_voltage)) {
dev_warn(&pdev->dev, "Invalid or missing keyup voltage\n");
return -EINVAL;
}
mc_data->keyup_voltage /= 1000;
ret = mc_keys_load_keymap(&pdev->dev, mc_data);
if (ret)
return ret;
input = devm_input_allocate_device(&pdev->dev);
if (IS_ERR(input)) {
dev_err(&pdev->dev, "failed to allocate input device\n");
return PTR_ERR(input);
}
input_set_drvdata(input, mc_data);
input->name = "headset-keys";
input->phys = "headset-keys/input0";
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
__set_bit(EV_KEY, input->evbit);
for (i = 0; i < mc_data->num_keys; i++)
__set_bit(mc_data->map[i].keycode, input->keybit);
if (device_property_read_bool(&pdev->dev, "autorepeat"))
__set_bit(EV_REP, input->evbit);
mc_data->input = input;
ret = mc_keys_setup_polling(mc_data, mc_keys_poll);
if (ret) {
dev_err(&pdev->dev, "Unable to set up polling: %d\n", ret);
return ret;
}
if (!device_property_read_u32(&pdev->dev, "poll-interval", &value))
mc_set_poll_interval(mc_data->poller, value);
ret = input_register_device(mc_data->input);
if (ret) {
dev_err(&pdev->dev, "Unable to register input device: %d\n", ret);
return ret;
}
}
INIT_DEFERRABLE_WORK(&mc_data->handler, adc_jack_handler);
mc_data->spk_ctl_gpio = devm_gpiod_get_optional(&pdev->dev,
"spk-con",
GPIOD_OUT_LOW);
if (IS_ERR(mc_data->spk_ctl_gpio))
return PTR_ERR(mc_data->spk_ctl_gpio);
mc_data->hp_ctl_gpio = devm_gpiod_get_optional(&pdev->dev,
"hp-con",
GPIOD_OUT_LOW);
if (IS_ERR(mc_data->hp_ctl_gpio))
return PTR_ERR(mc_data->hp_ctl_gpio);
mc_data->hp_det_gpio = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN);
if (IS_ERR(mc_data->hp_det_gpio))
return PTR_ERR(mc_data->hp_det_gpio);
mc_data->extcon = devm_extcon_dev_allocate(&pdev->dev, headset_extcon_cable);
if (IS_ERR(mc_data->extcon)) {
dev_err(&pdev->dev, "allocate extcon failed\n");
return PTR_ERR(mc_data->extcon);
}
ret = devm_extcon_dev_register(&pdev->dev, mc_data->extcon);
if (ret) {
dev_err(&pdev->dev, "failed to register extcon: %d\n", ret);
return ret;
}
ret = snd_soc_of_parse_audio_routing(card, "rockchip,audio-routing");
if (ret < 0)
dev_warn(&pdev->dev, "Audio routing invalid/unspecified\n");
snd_soc_card_set_drvdata(card, mc_data);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (ret) {
dev_err(&pdev->dev, "card register failed %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, card);
return ret;
}
最新发布