Commit a7d1a1eb authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Chris Ball

mmc: core: convert slot functions to managed allocation

This prepares for the addition of further slot functions.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent befe4048
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
static void mmc_host_classdev_release(struct device *dev) static void mmc_host_classdev_release(struct device *dev)
{ {
struct mmc_host *host = cls_dev_to_mmc_host(dev); struct mmc_host *host = cls_dev_to_mmc_host(dev);
mutex_destroy(&host->slot.lock);
kfree(host); kfree(host);
} }
...@@ -327,6 +328,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -327,6 +328,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
mmc_host_clk_init(host); mmc_host_clk_init(host);
mutex_init(&host->slot.lock);
host->slot.cd_irq = -EINVAL; host->slot.cd_irq = -EINVAL;
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
......
...@@ -29,6 +29,34 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) ...@@ -29,6 +29,34 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int mmc_gpio_alloc(struct mmc_host *host)
{
size_t len = strlen(dev_name(host->parent)) + 4;
struct mmc_gpio *ctx;
mutex_lock(&host->slot.lock);
ctx = host->slot.handler_priv;
if (!ctx) {
/*
* devm_kzalloc() can be called after device_initialize(), even
* before device_add(), i.e., between mmc_alloc_host() and
* mmc_add_host()
*/
ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + len,
GFP_KERNEL);
if (ctx) {
snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
ctx->cd_gpio = -EINVAL;
host->slot.handler_priv = ctx;
}
}
mutex_unlock(&host->slot.lock);
return ctx ? 0 : -ENOMEM;
}
int mmc_gpio_get_cd(struct mmc_host *host) int mmc_gpio_get_cd(struct mmc_host *host)
{ {
struct mmc_gpio *ctx = host->slot.handler_priv; struct mmc_gpio *ctx = host->slot.handler_priv;
...@@ -43,20 +71,24 @@ EXPORT_SYMBOL(mmc_gpio_get_cd); ...@@ -43,20 +71,24 @@ EXPORT_SYMBOL(mmc_gpio_get_cd);
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
{ {
size_t len = strlen(dev_name(host->parent)) + 4;
struct mmc_gpio *ctx; struct mmc_gpio *ctx;
int irq = gpio_to_irq(gpio); int irq = gpio_to_irq(gpio);
int ret; int ret;
ctx = kmalloc(sizeof(*ctx) + len, GFP_KERNEL); ret = mmc_gpio_alloc(host);
if (!ctx) if (ret < 0)
return -ENOMEM; return ret;
snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); ctx = host->slot.handler_priv;
ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label); ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
if (ret < 0) if (ret < 0)
goto egpioreq; /*
* don't bother freeing memory. It might still get used by other
* slot functions, in any case it will be freed, when the device
* is destroyed.
*/
return ret;
/* /*
* Even if gpio_to_irq() returns a valid IRQ number, the platform might * Even if gpio_to_irq() returns a valid IRQ number, the platform might
...@@ -80,13 +112,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) ...@@ -80,13 +112,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
host->caps |= MMC_CAP_NEEDS_POLL; host->caps |= MMC_CAP_NEEDS_POLL;
ctx->cd_gpio = gpio; ctx->cd_gpio = gpio;
host->slot.handler_priv = ctx;
return 0; return 0;
egpioreq:
kfree(ctx);
return ret;
} }
EXPORT_SYMBOL(mmc_gpio_request_cd); EXPORT_SYMBOL(mmc_gpio_request_cd);
...@@ -107,7 +134,5 @@ void mmc_gpio_free_cd(struct mmc_host *host) ...@@ -107,7 +134,5 @@ void mmc_gpio_free_cd(struct mmc_host *host)
ctx->cd_gpio = -EINVAL; ctx->cd_gpio = -EINVAL;
gpio_free(gpio); gpio_free(gpio);
host->slot.handler_priv = NULL;
kfree(ctx);
} }
EXPORT_SYMBOL(mmc_gpio_free_cd); EXPORT_SYMBOL(mmc_gpio_free_cd);
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define LINUX_MMC_HOST_H #define LINUX_MMC_HOST_H
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/fault-inject.h> #include <linux/fault-inject.h>
...@@ -154,6 +155,7 @@ struct mmc_async_req { ...@@ -154,6 +155,7 @@ struct mmc_async_req {
* struct mmc_slot - MMC slot functions * struct mmc_slot - MMC slot functions
* *
* @cd_irq: MMC/SD-card slot hotplug detection IRQ or -EINVAL * @cd_irq: MMC/SD-card slot hotplug detection IRQ or -EINVAL
* @lock: protect the @handler_priv pointer
* @handler_priv: MMC/SD-card slot context * @handler_priv: MMC/SD-card slot context
* *
* Some MMC/SD host controllers implement slot-functions like card and * Some MMC/SD host controllers implement slot-functions like card and
...@@ -163,6 +165,7 @@ struct mmc_async_req { ...@@ -163,6 +165,7 @@ struct mmc_async_req {
*/ */
struct mmc_slot { struct mmc_slot {
int cd_irq; int cd_irq;
struct mutex lock;
void *handler_priv; void *handler_priv;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment