slot-gpio.c 1.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Generic GPIO card-detect helper
 *
 * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mmc/host.h>
16
#include <linux/mmc/slot-gpio.h>
17 18 19
#include <linux/module.h>
#include <linux/slab.h>

20 21 22
struct mmc_gpio {
	unsigned int cd_gpio;
	char cd_label[0];
23 24
};

25
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
26 27 28 29 30 31
{
	/* Schedule a card detection after a debounce timeout */
	mmc_detect_change(dev_id, msecs_to_jiffies(100));
	return IRQ_HANDLED;
}

32
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
33 34
{
	size_t len = strlen(dev_name(host->parent)) + 4;
35
	struct mmc_gpio *ctx;
36
	int irq = gpio_to_irq(gpio);
37 38
	int ret;

39 40 41
	if (irq < 0)
		return irq;

42 43
	ctx = kmalloc(sizeof(*ctx) + len, GFP_KERNEL);
	if (!ctx)
44 45
		return -ENOMEM;

46
	snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
47

48
	ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
49 50 51
	if (ret < 0)
		goto egpioreq;

52 53 54
	ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt,
			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
			ctx->cd_label, host);
55 56 57
	if (ret < 0)
		goto eirqreq;

58
	ctx->cd_gpio = gpio;
59
	host->hotplug.irq = irq;
60
	host->hotplug.handler_priv = ctx;
61 62 63 64 65 66

	return 0;

eirqreq:
	gpio_free(gpio);
egpioreq:
67
	kfree(ctx);
68 69
	return ret;
}
70
EXPORT_SYMBOL(mmc_gpio_request_cd);
71

72
void mmc_gpio_free_cd(struct mmc_host *host)
73
{
74
	struct mmc_gpio *ctx = host->hotplug.handler_priv;
75

76
	if (!ctx)
77 78
		return;

79
	free_irq(host->hotplug.irq, host);
80 81
	gpio_free(ctx->cd_gpio);
	kfree(ctx);
82
}
83
EXPORT_SYMBOL(mmc_gpio_free_cd);