1*6014e902STakashi Iwai // SPDX-License-Identifier: GPL-2.0-only 2*6014e902STakashi Iwai // 3*6014e902STakashi Iwai // Common code for Cirrus side-codecs. 4*6014e902STakashi Iwai // 5*6014e902STakashi Iwai // Copyright (C) 2021, 2023 Cirrus Logic, Inc. and 6*6014e902STakashi Iwai // Cirrus Logic International Semiconductor Ltd. 7*6014e902STakashi Iwai 8*6014e902STakashi Iwai #include <linux/dev_printk.h> 9*6014e902STakashi Iwai #include <linux/gpio/consumer.h> 10*6014e902STakashi Iwai #include <linux/module.h> 11*6014e902STakashi Iwai 12*6014e902STakashi Iwai #include "cirrus_scodec.h" 13*6014e902STakashi Iwai 14*6014e902STakashi Iwai int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index, 15*6014e902STakashi Iwai int num_amps, int fixed_gpio_id) 16*6014e902STakashi Iwai { 17*6014e902STakashi Iwai struct gpio_desc *speaker_id_desc; 18*6014e902STakashi Iwai int speaker_id = -ENOENT; 19*6014e902STakashi Iwai 20*6014e902STakashi Iwai if (fixed_gpio_id >= 0) { 21*6014e902STakashi Iwai dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id); 22*6014e902STakashi Iwai speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN); 23*6014e902STakashi Iwai if (IS_ERR(speaker_id_desc)) { 24*6014e902STakashi Iwai speaker_id = PTR_ERR(speaker_id_desc); 25*6014e902STakashi Iwai return speaker_id; 26*6014e902STakashi Iwai } 27*6014e902STakashi Iwai speaker_id = gpiod_get_value_cansleep(speaker_id_desc); 28*6014e902STakashi Iwai gpiod_put(speaker_id_desc); 29*6014e902STakashi Iwai } else { 30*6014e902STakashi Iwai int base_index; 31*6014e902STakashi Iwai int gpios_per_amp; 32*6014e902STakashi Iwai int count; 33*6014e902STakashi Iwai int tmp; 34*6014e902STakashi Iwai int i; 35*6014e902STakashi Iwai 36*6014e902STakashi Iwai count = gpiod_count(dev, "spk-id"); 37*6014e902STakashi Iwai if (count > 0) { 38*6014e902STakashi Iwai speaker_id = 0; 39*6014e902STakashi Iwai gpios_per_amp = count / num_amps; 40*6014e902STakashi Iwai base_index = gpios_per_amp * amp_index; 41*6014e902STakashi Iwai 42*6014e902STakashi Iwai if (count % num_amps) 43*6014e902STakashi Iwai return -EINVAL; 44*6014e902STakashi Iwai 45*6014e902STakashi Iwai dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp); 46*6014e902STakashi Iwai 47*6014e902STakashi Iwai for (i = 0; i < gpios_per_amp; i++) { 48*6014e902STakashi Iwai speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index, 49*6014e902STakashi Iwai GPIOD_IN); 50*6014e902STakashi Iwai if (IS_ERR(speaker_id_desc)) { 51*6014e902STakashi Iwai speaker_id = PTR_ERR(speaker_id_desc); 52*6014e902STakashi Iwai break; 53*6014e902STakashi Iwai } 54*6014e902STakashi Iwai tmp = gpiod_get_value_cansleep(speaker_id_desc); 55*6014e902STakashi Iwai gpiod_put(speaker_id_desc); 56*6014e902STakashi Iwai if (tmp < 0) { 57*6014e902STakashi Iwai speaker_id = tmp; 58*6014e902STakashi Iwai break; 59*6014e902STakashi Iwai } 60*6014e902STakashi Iwai speaker_id |= tmp << i; 61*6014e902STakashi Iwai } 62*6014e902STakashi Iwai } 63*6014e902STakashi Iwai } 64*6014e902STakashi Iwai 65*6014e902STakashi Iwai dev_dbg(dev, "Speaker ID = %d\n", speaker_id); 66*6014e902STakashi Iwai 67*6014e902STakashi Iwai return speaker_id; 68*6014e902STakashi Iwai } 69*6014e902STakashi Iwai EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, "SND_HDA_CIRRUS_SCODEC"); 70*6014e902STakashi Iwai 71*6014e902STakashi Iwai MODULE_DESCRIPTION("HDA Cirrus side-codec library"); 72*6014e902STakashi Iwai MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); 73*6014e902STakashi Iwai MODULE_LICENSE("GPL"); 74