 349ab52446
			
		
	
	
	349ab52446
	
	
	
		
			
			This patch adds a primitive helper to support card hotplug detection on platforms, where a GPIO, capable of producing interrupts, is used for detection of card-insertion and -removal events. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Chris Ball <cjb@laptop.org>
		
			
				
	
	
		
			74 lines
		
	
	
	
		
			1.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			74 lines
		
	
	
	
		
			1.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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>
 | |
| #include <linux/module.h>
 | |
| #include <linux/slab.h>
 | |
| 
 | |
| struct mmc_cd_gpio {
 | |
| 	unsigned int gpio;
 | |
| 	char label[0];
 | |
| };
 | |
| 
 | |
| static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
 | |
| {
 | |
| 	/* Schedule a card detection after a debounce timeout */
 | |
| 	mmc_detect_change(dev_id, msecs_to_jiffies(100));
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| 
 | |
| int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
 | |
| 			unsigned int irq, unsigned long flags)
 | |
| {
 | |
| 	size_t len = strlen(dev_name(host->parent)) + 4;
 | |
| 	struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
 | |
| 	int ret;
 | |
| 
 | |
| 	if (!cd)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	snprintf(cd->label, len, "%s cd", dev_name(host->parent));
 | |
| 
 | |
| 	ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label);
 | |
| 	if (ret < 0)
 | |
| 		goto egpioreq;
 | |
| 
 | |
| 	ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
 | |
| 				   flags, cd->label, host);
 | |
| 	if (ret < 0)
 | |
| 		goto eirqreq;
 | |
| 
 | |
| 	cd->gpio = gpio;
 | |
| 	host->hotplug.irq = irq;
 | |
| 	host->hotplug.handler_priv = cd;
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| eirqreq:
 | |
| 	gpio_free(gpio);
 | |
| egpioreq:
 | |
| 	kfree(cd);
 | |
| 	return ret;
 | |
| }
 | |
| EXPORT_SYMBOL(mmc_cd_gpio_request);
 | |
| 
 | |
| void mmc_cd_gpio_free(struct mmc_host *host)
 | |
| {
 | |
| 	struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
 | |
| 
 | |
| 	free_irq(host->hotplug.irq, host);
 | |
| 	gpio_free(cd->gpio);
 | |
| 	kfree(cd);
 | |
| }
 | |
| EXPORT_SYMBOL(mmc_cd_gpio_free);
 |