mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 16:41:39 +00:00
tlv320adc3xxx: Allow MICBIAS pins to be used as
Merge series from Ricard Wanderlof <ricard.wanderlof@axis.com>: In some cases, depending on system design, the MICBIAS pins on the chip are not needed as such, but a couple of extra GPIO pins would be useful. This patch allows the MICBIAS pins to be configured in the device tree as general purpose output pins, controlled via the GPIO framework. Owing to their originally intended purpose there are some limitations: when the MICBIAS pins are deactivated, they will float, so will likely need a pulldown in many applications. When activated, they will assume the voltage specified by the micbias1-vg and micbias2-vg properties, respectively, meaning that the resulting output voltage will be 2.0 V, 2.5 V or AVDD .
This commit is contained in:
commit
b493c97d08
@ -82,6 +82,26 @@ properties:
|
||||
Note that there is currently no support for reading the GPIO pins as
|
||||
inputs.
|
||||
|
||||
ti,micbias1-gpo:
|
||||
type: boolean
|
||||
description: |
|
||||
When set, the MICBIAS1 pin may be controlled via the GPIO framework,
|
||||
as pin number 3 on the device.
|
||||
|
||||
In this mode, when the pin is activated, it will be set to the voltage
|
||||
specified by the ti,micbias1-vg property. When deactivated, the pin will
|
||||
float.
|
||||
|
||||
ti,micbias2-gpo:
|
||||
type: boolean
|
||||
description: |
|
||||
When set, the MICBIAS2 pin may be controlled via the GPIO framework,
|
||||
as pin number 4 on the device.
|
||||
|
||||
In this mode, when the pin is activated, it will be set to the voltage
|
||||
specified by the ti,micbias2-vg property. When deactivated, the pin will
|
||||
float.
|
||||
|
||||
ti,micbias1-vg:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
@ -104,6 +124,10 @@ properties:
|
||||
description: |
|
||||
Mic bias voltage output on MICBIAS2 pin
|
||||
|
||||
dependencies:
|
||||
ti,micbias1-gpo: ['ti,micbias1-vg']
|
||||
ti,micbias2-gpo: ['ti,micbias2-vg']
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -39,9 +39,10 @@
|
||||
*/
|
||||
|
||||
#define ADC3XXX_MICBIAS_PINS 2
|
||||
#define ADC3XXX_GPIO_PINS 2
|
||||
|
||||
/* Number of GPIO pins exposed via the gpiolib interface */
|
||||
#define ADC3XXX_GPIOS_MAX 2
|
||||
#define ADC3XXX_GPIOS_MAX (ADC3XXX_MICBIAS_PINS + ADC3XXX_GPIO_PINS)
|
||||
|
||||
#define ADC3XXX_RATES SNDRV_PCM_RATE_8000_96000
|
||||
#define ADC3XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
@ -320,7 +321,8 @@ struct adc3xxx {
|
||||
struct gpio_desc *rst_pin;
|
||||
unsigned int pll_mode;
|
||||
unsigned int sysclk;
|
||||
unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set) */
|
||||
unsigned int gpio_cfg[ADC3XXX_GPIO_PINS]; /* value+1 (0 => not set) */
|
||||
unsigned int micbias_gpo[ADC3XXX_MICBIAS_PINS]; /* 1 => pin is GPO */
|
||||
unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS];
|
||||
int master;
|
||||
u8 page_no;
|
||||
@ -328,7 +330,7 @@ struct adc3xxx {
|
||||
struct gpio_chip gpio_chip;
|
||||
};
|
||||
|
||||
static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = {
|
||||
static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIO_PINS] = {
|
||||
ADC3XXX_GPIO1_CTRL,
|
||||
ADC3XXX_GPIO2_CTRL
|
||||
};
|
||||
@ -959,14 +961,23 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
if (offset >= ADC3XXX_GPIOS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) {
|
||||
/* GPIO1 is offset 0, GPIO2 is offset 1 */
|
||||
/* We check here that the GPIO pins are either not configured in the
|
||||
* DT, or that they purposely are set as outputs.
|
||||
/* We check here that the GPIO pins are either not configured
|
||||
* in the DT, or that they purposely are set as outputs.
|
||||
* (Input mode not yet implemented).
|
||||
*/
|
||||
if (adc3xxx->gpio_cfg[offset] != 0 &&
|
||||
adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1)
|
||||
return -EINVAL;
|
||||
} else if (offset >= ADC3XXX_GPIO_PINS && offset < ADC3XXX_GPIOS_MAX) {
|
||||
/* MICBIAS1 is offset 2, MICBIAS2 is offset 3 */
|
||||
/* We check here if the MICBIAS pins are in fact configured
|
||||
* as GPOs.
|
||||
*/
|
||||
if (!adc3xxx->micbias_gpo[offset - ADC3XXX_GPIO_PINS])
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -976,6 +987,21 @@ static int adc3xxx_gpio_direction_out(struct gpio_chip *chip,
|
||||
{
|
||||
struct adc3xxx *adc3xxx = gpiochip_get_data(chip);
|
||||
|
||||
/* For the MICBIAS pins, they are by definition outputs. */
|
||||
if (offset >= ADC3XXX_GPIO_PINS) {
|
||||
unsigned int vg;
|
||||
unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
|
||||
|
||||
if (value)
|
||||
vg = adc3xxx->micbias_vg[micbias];
|
||||
else
|
||||
vg = ADC3XXX_MICBIAS_OFF;
|
||||
return regmap_update_bits(adc3xxx->regmap,
|
||||
ADC3XXX_MICBIAS_CTRL,
|
||||
ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias],
|
||||
vg << adc3xxx_micbias_shift[micbias]);
|
||||
}
|
||||
|
||||
/* Set GPIO output function. */
|
||||
return regmap_update_bits(adc3xxx->regmap,
|
||||
adc3xxx_gpio_ctrl_reg[offset],
|
||||
@ -1004,9 +1030,17 @@ static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
/* We only allow output pins, so just read the value set in the output
|
||||
* pin register field.
|
||||
*/
|
||||
/* We only allow output pins, so just read the value prevously set. */
|
||||
if (offset >= ADC3XXX_GPIO_PINS) {
|
||||
/* MICBIAS pins */
|
||||
unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
|
||||
|
||||
ret = regmap_read(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ((regval >> adc3xxx_micbias_shift[micbias]) & ADC3XXX_MICBIAS_MASK) !=
|
||||
ADC3XXX_MICBIAS_OFF;
|
||||
}
|
||||
ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1048,7 +1082,7 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
|
||||
* This allows us to set up things which are not software
|
||||
* controllable GPIOs, such as PDM microphone I/O,
|
||||
*/
|
||||
for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) {
|
||||
for (gpio = 0; gpio < ADC3XXX_GPIO_PINS; gpio++) {
|
||||
unsigned int cfg = adc3xxx->gpio_cfg[gpio];
|
||||
|
||||
if (cfg) {
|
||||
@ -1060,9 +1094,15 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up micbias voltage */
|
||||
/* Set up micbias voltage. */
|
||||
/* If pin is configured as GPO, set off initially. */
|
||||
for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) {
|
||||
unsigned int vg = adc3xxx->micbias_vg[micbias];
|
||||
unsigned int vg;
|
||||
|
||||
if (adc3xxx->micbias_gpo[micbias])
|
||||
vg = ADC3XXX_MICBIAS_OFF;
|
||||
else
|
||||
vg = adc3xxx->micbias_vg[micbias];
|
||||
|
||||
regmap_update_bits(adc3xxx->regmap,
|
||||
ADC3XXX_MICBIAS_CTRL,
|
||||
@ -1090,7 +1130,18 @@ static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx,
|
||||
static int adc3xxx_parse_dt_micbias_gpo(struct adc3xxx *adc3xxx,
|
||||
const char *propname,
|
||||
unsigned int *cfg)
|
||||
{
|
||||
struct device *dev = adc3xxx->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
*cfg = of_property_read_bool(np, propname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adc3xxx_parse_dt_micbias_vg(struct adc3xxx *adc3xxx,
|
||||
const char *propname, unsigned int *vg)
|
||||
{
|
||||
struct device *dev = adc3xxx->dev;
|
||||
@ -1382,16 +1433,28 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c)
|
||||
dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk));
|
||||
}
|
||||
|
||||
/* Configure mode for DMDIN/GPIO1 pin */
|
||||
ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]);
|
||||
if (ret < 0)
|
||||
goto err_unprepare_mclk;
|
||||
/* Configure mode for DMCLK/GPIO2 pin */
|
||||
ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]);
|
||||
if (ret < 0)
|
||||
goto err_unprepare_mclk;
|
||||
ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
|
||||
/* Configure mode for MICBIAS1: as Mic Bias output or GPO */
|
||||
ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias1-gpo", &adc3xxx->micbias_gpo[0]);
|
||||
if (ret < 0)
|
||||
goto err_unprepare_mclk;
|
||||
ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
|
||||
/* Configure mode for MICBIAS2: as Mic Bias output or GPO */
|
||||
ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias2-gpo", &adc3xxx->micbias_gpo[1]);
|
||||
if (ret < 0)
|
||||
goto err_unprepare_mclk;
|
||||
/* Configure voltage for MICBIAS1 pin (ON voltage when used as GPO) */
|
||||
ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
|
||||
if (ret < 0)
|
||||
goto err_unprepare_mclk;
|
||||
/* Configure voltage for MICBIAS2 pin (ON voltage when used as GPO) */
|
||||
ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
|
||||
if (ret < 0)
|
||||
goto err_unprepare_mclk;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user