Ejemplo n.º 1
0
/**
 * mmc_gpiod_request_cd - request a gpio descriptor for card-detection
 * @host: mmc host
 * @con_id: function within the GPIO consumer
 * @idx: index of the GPIO to obtain in the consumer
 * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
 * @debounce: debounce time in microseconds
 * @gpio_invert: will return whether the GPIO line is inverted or not, set
 * to NULL to ignore
 *
 * Use this function in place of mmc_gpio_request_cd() to use the GPIO
 * descriptor API.  Note that it is paired with mmc_gpiod_free_cd() not
 * mmc_gpio_free_cd().  Note also that it must be called prior to mmc_add_host()
 * otherwise the caller must also call mmc_gpiod_request_cd_irq().
 *
 * Returns zero on success, else an error.
 */
int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
			 unsigned int idx, bool override_active_level,
			 unsigned int debounce, bool *gpio_invert)
{
	struct mmc_gpio *ctx;
	struct gpio_desc *desc;
	int ret;

	ret = mmc_gpio_alloc(host);
	if (ret < 0)
		return ret;

	ctx = host->slot.handler_priv;

	if (!con_id)
		con_id = ctx->cd_label;

	desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
	if (IS_ERR(desc))
		return PTR_ERR(desc);

	if (debounce) {
		ret = gpiod_set_debounce(desc, debounce);
		if (ret < 0)
			return ret;
	}

	if (gpio_invert)
		*gpio_invert = !gpiod_is_active_low(desc);

	ctx->override_cd_active_level = override_active_level;
	ctx->cd_gpio = desc;

	return 0;
}
Ejemplo n.º 2
0
/**
 * mmc_gpiod_request_ro - request a gpio descriptor for write protection
 * @host: mmc host
 * @con_id: function within the GPIO consumer
 * @idx: index of the GPIO to obtain in the consumer
 * @debounce: debounce time in microseconds
 * @gpio_invert: will return whether the GPIO line is inverted or not,
 * set to NULL to ignore
 *
 * Returns zero on success, else an error.
 */
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
			 unsigned int idx,
			 unsigned int debounce, bool *gpio_invert)
{
	struct mmc_gpio *ctx = host->slot.handler_priv;
	struct gpio_desc *desc;
	int ret;

	desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
	if (IS_ERR(desc))
		return PTR_ERR(desc);

	if (debounce) {
		ret = gpiod_set_debounce(desc, debounce);
		if (ret < 0)
			return ret;
	}

	if (gpio_invert)
		*gpio_invert = !gpiod_is_active_low(desc);

	ctx->ro_gpio = desc;

	return 0;
}
Ejemplo n.º 3
0
static int cs53l30_i2c_probe(struct i2c_client *client,
			     const struct i2c_device_id *id)
{
	const struct device_node *np = client->dev.of_node;
	struct device *dev = &client->dev;
	struct cs53l30_private *cs53l30;
	unsigned int devid = 0;
	unsigned int reg;
	int ret = 0, i;
	u8 val;

	cs53l30 = devm_kzalloc(dev, sizeof(*cs53l30), GFP_KERNEL);
	if (!cs53l30)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(cs53l30->supplies); i++)
		cs53l30->supplies[i].supply = cs53l30_supply_names[i];

	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs53l30->supplies),
				      cs53l30->supplies);
	if (ret) {
		dev_err(dev, "failed to get supplies: %d\n", ret);
		return ret;
	}

	ret = regulator_bulk_enable(ARRAY_SIZE(cs53l30->supplies),
				    cs53l30->supplies);
	if (ret) {
		dev_err(dev, "failed to enable supplies: %d\n", ret);
		return ret;
	}

	/* Reset the Device */
	cs53l30->reset_gpio = devm_gpiod_get_optional(dev, "reset",
						      GPIOD_OUT_LOW);
	if (IS_ERR(cs53l30->reset_gpio)) {
		ret = PTR_ERR(cs53l30->reset_gpio);
		goto error;
	}

	gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);

	i2c_set_clientdata(client, cs53l30);

	cs53l30->mclk_rate = 0;

	cs53l30->regmap = devm_regmap_init_i2c(client, &cs53l30_regmap);
	if (IS_ERR(cs53l30->regmap)) {
		ret = PTR_ERR(cs53l30->regmap);
		dev_err(dev, "regmap_init() failed: %d\n", ret);
		goto error;
	}

	/* Initialize codec */
	ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_AB, &reg);
	devid = reg << 12;

	ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_CD, &reg);
	devid |= reg << 4;

	ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_E, &reg);
	devid |= (reg & 0xF0) >> 4;

	if (devid != CS53L30_DEVID) {
		ret = -ENODEV;
		dev_err(dev, "Device ID (%X). Expected %X\n",
			devid, CS53L30_DEVID);
		goto error;
	}

	ret = regmap_read(cs53l30->regmap, CS53L30_REVID, &reg);
	if (ret < 0) {
		dev_err(dev, "failed to get Revision ID: %d\n", ret);
		goto error;
	}

	/* Check if MCLK provided */
	cs53l30->mclk = devm_clk_get(dev, "mclk");
	if (IS_ERR(cs53l30->mclk)) {
		if (PTR_ERR(cs53l30->mclk) != -ENOENT) {
			ret = PTR_ERR(cs53l30->mclk);
			goto error;
		}
		/* Otherwise mark the mclk pointer to NULL */
		cs53l30->mclk = NULL;
	}

	/* Fetch the MUTE control */
	cs53l30->mute_gpio = devm_gpiod_get_optional(dev, "mute",
						     GPIOD_OUT_HIGH);
	if (IS_ERR(cs53l30->mute_gpio)) {
		ret = PTR_ERR(cs53l30->mute_gpio);
		goto error;
	}

	if (cs53l30->mute_gpio) {
		/* Enable MUTE controls via MUTE pin */
		regmap_write(cs53l30->regmap, CS53L30_MUTEP_CTL1,
			     CS53L30_MUTEP_CTL1_MUTEALL);
		/* Flip the polarity of MUTE pin */
		if (gpiod_is_active_low(cs53l30->mute_gpio))
			regmap_update_bits(cs53l30->regmap, CS53L30_MUTEP_CTL2,
					   CS53L30_MUTE_PIN_POLARITY, 0);
	}

	if (!of_property_read_u8(np, "cirrus,micbias-lvl", &val))
		regmap_update_bits(cs53l30->regmap, CS53L30_MICBIAS_CTL,
				   CS53L30_MIC_BIAS_CTRL_MASK, val);

	if (of_property_read_bool(np, "cirrus,use-sdout2"))
		cs53l30->use_sdout2 = true;

	dev_info(dev, "Cirrus Logic CS53L30, Revision: %02X\n", reg & 0xFF);

	ret = snd_soc_register_codec(dev, &cs53l30_driver, &cs53l30_dai, 1);
	if (ret) {
		dev_err(dev, "failed to register codec: %d\n", ret);
		goto error;
	}

	return 0;

error:
	regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
			       cs53l30->supplies);
	return ret;
}