blob: 5530def54e5bbf8a08be34e3ce4ea2534a8802da [file] [log] [blame]
Anton Vorontsov9c43df52008-12-30 18:15:28 +03001/*
2 * OpenFirmware bindings for the MMC-over-SPI driver
3 *
4 * Copyright (c) MontaVista Software, Inc. 2008.
5 *
6 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Anton Vorontsov9c43df52008-12-30 18:15:28 +030018#include <linux/gpio.h>
19#include <linux/of.h>
20#include <linux/of_gpio.h>
21#include <linux/spi/spi.h>
22#include <linux/spi/mmc_spi.h>
23#include <linux/mmc/core.h>
24#include <linux/mmc/host.h>
25
Grant Likely02d9e582009-11-04 22:43:35 -070026MODULE_LICENSE("GPL");
27
Anton Vorontsov9c43df52008-12-30 18:15:28 +030028enum {
29 CD_GPIO = 0,
30 WP_GPIO,
31 NUM_GPIOS,
32};
33
34struct of_mmc_spi {
35 int gpios[NUM_GPIOS];
36 bool alow_gpios[NUM_GPIOS];
Esben Haabendal290293e2011-03-07 20:45:28 -070037 int detect_irq;
Anton Vorontsov9c43df52008-12-30 18:15:28 +030038 struct mmc_spi_platform_data pdata;
39};
40
41static struct of_mmc_spi *to_of_mmc_spi(struct device *dev)
42{
43 return container_of(dev->platform_data, struct of_mmc_spi, pdata);
44}
45
46static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num)
47{
48 struct of_mmc_spi *oms = to_of_mmc_spi(dev);
49 bool active_low = oms->alow_gpios[gpio_num];
50 bool value = gpio_get_value(oms->gpios[gpio_num]);
51
52 return active_low ^ value;
53}
54
55static int of_mmc_spi_get_cd(struct device *dev)
56{
57 return of_mmc_spi_read_gpio(dev, CD_GPIO);
58}
59
60static int of_mmc_spi_get_ro(struct device *dev)
61{
62 return of_mmc_spi_read_gpio(dev, WP_GPIO);
63}
64
Esben Haabendal290293e2011-03-07 20:45:28 -070065static int of_mmc_spi_init(struct device *dev,
66 irqreturn_t (*irqhandler)(int, void *), void *mmc)
67{
68 struct of_mmc_spi *oms = to_of_mmc_spi(dev);
69
70 return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 0,
71 dev_name(dev), mmc);
72}
73
74static void of_mmc_spi_exit(struct device *dev, void *mmc)
75{
76 struct of_mmc_spi *oms = to_of_mmc_spi(dev);
77
78 free_irq(oms->detect_irq, mmc);
79}
80
Anton Vorontsov9c43df52008-12-30 18:15:28 +030081struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
82{
83 struct device *dev = &spi->dev;
Grant Likely61c7a082010-04-13 16:12:29 -070084 struct device_node *np = dev->of_node;
Anton Vorontsov9c43df52008-12-30 18:15:28 +030085 struct of_mmc_spi *oms;
86 const u32 *voltage_ranges;
87 int num_ranges;
88 int i;
89 int ret = -EINVAL;
90
91 if (dev->platform_data || !np)
92 return dev->platform_data;
93
94 oms = kzalloc(sizeof(*oms), GFP_KERNEL);
95 if (!oms)
96 return NULL;
97
98 voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
99 num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
100 if (!voltage_ranges || !num_ranges) {
101 dev_err(dev, "OF: voltage-ranges unspecified\n");
102 goto err_ocr;
103 }
104
105 for (i = 0; i < num_ranges; i++) {
106 const int j = i * 2;
107 u32 mask;
108
109 mask = mmc_vddrange_to_ocrmask(voltage_ranges[j],
110 voltage_ranges[j + 1]);
111 if (!mask) {
112 ret = -EINVAL;
113 dev_err(dev, "OF: voltage-range #%d is invalid\n", i);
114 goto err_ocr;
115 }
116 oms->pdata.ocr_mask |= mask;
117 }
118
119 for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
120 enum of_gpio_flags gpio_flags;
121
122 oms->gpios[i] = of_get_gpio_flags(np, i, &gpio_flags);
123 if (!gpio_is_valid(oms->gpios[i]))
124 continue;
125
Kay Sievers48f81512009-03-24 16:38:21 -0700126 ret = gpio_request(oms->gpios[i], dev_name(dev));
Anton Vorontsov9c43df52008-12-30 18:15:28 +0300127 if (ret < 0) {
128 oms->gpios[i] = -EINVAL;
129 continue;
130 }
131
132 if (gpio_flags & OF_GPIO_ACTIVE_LOW)
133 oms->alow_gpios[i] = true;
134 }
135
136 if (gpio_is_valid(oms->gpios[CD_GPIO]))
137 oms->pdata.get_cd = of_mmc_spi_get_cd;
138 if (gpio_is_valid(oms->gpios[WP_GPIO]))
139 oms->pdata.get_ro = of_mmc_spi_get_ro;
140
Esben Haabendal290293e2011-03-07 20:45:28 -0700141 oms->detect_irq = irq_of_parse_and_map(np, 0);
142 if (oms->detect_irq != NO_IRQ) {
143 oms->pdata.init = of_mmc_spi_init;
144 oms->pdata.exit = of_mmc_spi_exit;
145 } else {
146 oms->pdata.caps |= MMC_CAP_NEEDS_POLL;
147 }
Anton Vorontsov9c43df52008-12-30 18:15:28 +0300148
149 dev->platform_data = &oms->pdata;
150 return dev->platform_data;
151err_ocr:
152 kfree(oms);
153 return NULL;
154}
155EXPORT_SYMBOL(mmc_spi_get_pdata);
156
157void mmc_spi_put_pdata(struct spi_device *spi)
158{
159 struct device *dev = &spi->dev;
Grant Likely61c7a082010-04-13 16:12:29 -0700160 struct device_node *np = dev->of_node;
Anton Vorontsov9c43df52008-12-30 18:15:28 +0300161 struct of_mmc_spi *oms = to_of_mmc_spi(dev);
162 int i;
163
164 if (!dev->platform_data || !np)
165 return;
166
167 for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
168 if (gpio_is_valid(oms->gpios[i]))
169 gpio_free(oms->gpios[i]);
170 }
171 kfree(oms);
172 dev->platform_data = NULL;
173}
174EXPORT_SYMBOL(mmc_spi_put_pdata);