Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/mmc/core/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  slot-gpio.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Generic GPIO card-detect helper
 *
 * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 */


#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/slab.h>

#include "slot-gpio.h"

struct mmc_gpio {
 struct gpio_desc *ro_gpio;
 struct gpio_desc *cd_gpio;
 irq_handler_t cd_gpio_isr;
 char *ro_label;
 char *cd_label;
 u32 cd_debounce_delay_ms;
 int cd_irq;
};

static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
 /* Schedule a card detection after a debounce timeout */
 struct mmc_host *host = dev_id;
 struct mmc_gpio *ctx = host->slot.handler_priv;

 host->trigger_card_event = true;
 mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms));

 return IRQ_HANDLED;
}

int mmc_gpio_alloc(struct mmc_host *host)
{
 const char *devname = dev_name(host->parent);
 struct mmc_gpio *ctx;

 ctx = devm_kzalloc(host->parent, sizeof(*ctx), GFP_KERNEL);
 if (!ctx)
  return -ENOMEM;

 ctx->cd_debounce_delay_ms = 200;
 ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s cd", devname);
 if (!ctx->cd_label)
  return -ENOMEM;
 ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s ro", devname);
 if (!ctx->ro_label)
  return -ENOMEM;
 ctx->cd_irq = -EINVAL;
 host->slot.handler_priv = ctx;
 host->slot.cd_irq = -EINVAL;

 return 0;
}

void mmc_gpio_set_cd_irq(struct mmc_host *host, int irq)
{
 struct mmc_gpio *ctx = host->slot.handler_priv;

 if (!ctx || irq < 0)
  return;

 ctx->cd_irq = irq;
}
EXPORT_SYMBOL(mmc_gpio_set_cd_irq);

int mmc_gpio_get_ro(struct mmc_host *host)
{
 struct mmc_gpio *ctx = host->slot.handler_priv;
 int cansleep;

 if (!ctx || !ctx->ro_gpio)
  return -ENOSYS;

 cansleep = gpiod_cansleep(ctx->ro_gpio);
 return cansleep ?
  gpiod_get_value_cansleep(ctx->ro_gpio) :
  gpiod_get_value(ctx->ro_gpio);
}
EXPORT_SYMBOL(mmc_gpio_get_ro);

int mmc_gpio_get_cd(struct mmc_host *host)
{
 struct mmc_gpio *ctx = host->slot.handler_priv;
 int cansleep;

 if (!ctx || !ctx->cd_gpio)
  return -ENOSYS;

 cansleep = gpiod_cansleep(ctx->cd_gpio);
 return cansleep ?
  gpiod_get_value_cansleep(ctx->cd_gpio) :
  gpiod_get_value(ctx->cd_gpio);
}
EXPORT_SYMBOL(mmc_gpio_get_cd);

void mmc_gpiod_request_cd_irq(struct mmc_host *host)
{
 struct mmc_gpio *ctx = host->slot.handler_priv;
 int irq = -EINVAL;
 int ret;

 if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
  return;

 /*
 * Do not use IRQ if the platform prefers to poll, e.g., because that
 * IRQ number is already used by another unit and cannot be shared.
 */

 if (ctx->cd_irq >= 0)
  irq = ctx->cd_irq;
 else if (!(host->caps & MMC_CAP_NEEDS_POLL))
  irq = gpiod_to_irq(ctx->cd_gpio);

 if (irq >= 0) {
  if (!ctx->cd_gpio_isr)
   ctx->cd_gpio_isr = mmc_gpio_cd_irqt;
  ret = devm_request_threaded_irq(host->parent, irq,
   NULL, ctx->cd_gpio_isr,
   IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
   ctx->cd_label, host);
  if (ret < 0)
   irq = ret;
 }

 host->slot.cd_irq = irq;

 if (irq < 0)
  host->caps |= MMC_CAP_NEEDS_POLL;
}
EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);

int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on)
{
 int ret = 0;

 if (!(host->caps & MMC_CAP_CD_WAKE) ||
     host->slot.cd_irq < 0 ||
     on == host->slot.cd_wake_enabled)
  return 0;

 if (on) {
  ret = enable_irq_wake(host->slot.cd_irq);
  host->slot.cd_wake_enabled = !ret;
 } else {
  disable_irq_wake(host->slot.cd_irq);
  host->slot.cd_wake_enabled = false;
 }

 return ret;
}
EXPORT_SYMBOL(mmc_gpio_set_cd_wake);

/**
 * 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
 *
 * Note that this 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)
{
 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);

 /* Update default label if no con_id provided */
 if (!con_id)
  gpiod_set_consumer_name(desc, ctx->cd_label);

 if (debounce) {
  ret = gpiod_set_debounce(desc, debounce);
  if (ret < 0)
   ctx->cd_debounce_delay_ms = debounce / 1000;
 }

 /* override forces default (active-low) polarity ... */
 if (override_active_level && !gpiod_is_active_low(desc))
  gpiod_toggle_active_low(desc);

 /* ... or active-high */
 if (host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)
  gpiod_toggle_active_low(desc);

 ctx->cd_gpio = desc;

 return 0;
}
EXPORT_SYMBOL(mmc_gpiod_request_cd);

/**
 * mmc_gpiod_set_cd_config - set config for card-detection GPIO
 * @host: mmc host
 * @config: Generic pinconf config (from pinconf_to_config_packed())
 *
 * This can be used by mmc host drivers to fixup a card-detection GPIO's config
 * (e.g. set PIN_CONFIG_BIAS_PULL_UP) after acquiring the GPIO descriptor
 * through mmc_gpiod_request_cd().
 *
 * Returns:
 * 0 on success, or a negative errno value on error.
 */

int mmc_gpiod_set_cd_config(struct mmc_host *host, unsigned long config)
{
 struct mmc_gpio *ctx = host->slot.handler_priv;

 return gpiod_set_config(ctx->cd_gpio, config);
}
EXPORT_SYMBOL(mmc_gpiod_set_cd_config);

bool mmc_host_can_gpio_cd(struct mmc_host *host)
{
 struct mmc_gpio *ctx = host->slot.handler_priv;

 return ctx->cd_gpio ? true : false;
}
EXPORT_SYMBOL(mmc_host_can_gpio_cd);

/**
 * 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
 *
 * 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)
{
 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);

 /* Update default label if no con_id provided */
 if (!con_id)
  gpiod_set_consumer_name(desc, ctx->ro_label);

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

 if (host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH)
  gpiod_toggle_active_low(desc);

 ctx->ro_gpio = desc;

 return 0;
}
EXPORT_SYMBOL(mmc_gpiod_request_ro);

bool mmc_host_can_gpio_ro(struct mmc_host *host)
{
 struct mmc_gpio *ctx = host->slot.handler_priv;

 return ctx->ro_gpio ? true : false;
}
EXPORT_SYMBOL(mmc_host_can_gpio_ro);

Messung V0.5
C=89 H=96 G=92

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.