/** * 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; }
/** * 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; }
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, ®); devid = reg << 12; ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_CD, ®); devid |= reg << 4; ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_E, ®); 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, ®); 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; }