19c43df57SAnton Vorontsov /* 29c43df57SAnton Vorontsov * OpenFirmware bindings for the MMC-over-SPI driver 39c43df57SAnton Vorontsov * 49c43df57SAnton Vorontsov * Copyright (c) MontaVista Software, Inc. 2008. 59c43df57SAnton Vorontsov * 69c43df57SAnton Vorontsov * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 79c43df57SAnton Vorontsov * 89c43df57SAnton Vorontsov * This program is free software; you can redistribute it and/or modify it 99c43df57SAnton Vorontsov * under the terms of the GNU General Public License as published by the 109c43df57SAnton Vorontsov * Free Software Foundation; either version 2 of the License, or (at your 119c43df57SAnton Vorontsov * option) any later version. 129c43df57SAnton Vorontsov */ 139c43df57SAnton Vorontsov 149c43df57SAnton Vorontsov #include <linux/kernel.h> 159c43df57SAnton Vorontsov #include <linux/module.h> 169c43df57SAnton Vorontsov #include <linux/device.h> 175a0e3ad6STejun Heo #include <linux/slab.h> 18b2fce6adSDavid Miller #include <linux/irq.h> 199c43df57SAnton Vorontsov #include <linux/gpio.h> 209c43df57SAnton Vorontsov #include <linux/of.h> 219c43df57SAnton Vorontsov #include <linux/of_gpio.h> 22b2fce6adSDavid Miller #include <linux/of_irq.h> 239c43df57SAnton Vorontsov #include <linux/spi/spi.h> 249c43df57SAnton Vorontsov #include <linux/spi/mmc_spi.h> 259c43df57SAnton Vorontsov #include <linux/mmc/core.h> 269c43df57SAnton Vorontsov #include <linux/mmc/host.h> 279c43df57SAnton Vorontsov 28b9c350a0SWanlong Gao /* For archs that don't support NO_IRQ (such as mips), provide a dummy value */ 29b9c350a0SWanlong Gao #ifndef NO_IRQ 30b9c350a0SWanlong Gao #define NO_IRQ 0 31b9c350a0SWanlong Gao #endif 32b9c350a0SWanlong Gao 3302d9e58eSGrant Likely MODULE_LICENSE("GPL"); 3402d9e58eSGrant Likely 359c43df57SAnton Vorontsov enum { 369c43df57SAnton Vorontsov CD_GPIO = 0, 379c43df57SAnton Vorontsov WP_GPIO, 389c43df57SAnton Vorontsov NUM_GPIOS, 399c43df57SAnton Vorontsov }; 409c43df57SAnton Vorontsov 419c43df57SAnton Vorontsov struct of_mmc_spi { 429c43df57SAnton Vorontsov int gpios[NUM_GPIOS]; 439c43df57SAnton Vorontsov bool alow_gpios[NUM_GPIOS]; 44290293edSEsben Haabendal int detect_irq; 459c43df57SAnton Vorontsov struct mmc_spi_platform_data pdata; 469c43df57SAnton Vorontsov }; 479c43df57SAnton Vorontsov 489c43df57SAnton Vorontsov static struct of_mmc_spi *to_of_mmc_spi(struct device *dev) 499c43df57SAnton Vorontsov { 509c43df57SAnton Vorontsov return container_of(dev->platform_data, struct of_mmc_spi, pdata); 519c43df57SAnton Vorontsov } 529c43df57SAnton Vorontsov 539c43df57SAnton Vorontsov static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num) 549c43df57SAnton Vorontsov { 559c43df57SAnton Vorontsov struct of_mmc_spi *oms = to_of_mmc_spi(dev); 569c43df57SAnton Vorontsov bool active_low = oms->alow_gpios[gpio_num]; 579c43df57SAnton Vorontsov bool value = gpio_get_value(oms->gpios[gpio_num]); 589c43df57SAnton Vorontsov 599c43df57SAnton Vorontsov return active_low ^ value; 609c43df57SAnton Vorontsov } 619c43df57SAnton Vorontsov 629c43df57SAnton Vorontsov static int of_mmc_spi_get_cd(struct device *dev) 639c43df57SAnton Vorontsov { 649c43df57SAnton Vorontsov return of_mmc_spi_read_gpio(dev, CD_GPIO); 659c43df57SAnton Vorontsov } 669c43df57SAnton Vorontsov 679c43df57SAnton Vorontsov static int of_mmc_spi_get_ro(struct device *dev) 689c43df57SAnton Vorontsov { 699c43df57SAnton Vorontsov return of_mmc_spi_read_gpio(dev, WP_GPIO); 709c43df57SAnton Vorontsov } 719c43df57SAnton Vorontsov 72290293edSEsben Haabendal static int of_mmc_spi_init(struct device *dev, 73290293edSEsben Haabendal irqreturn_t (*irqhandler)(int, void *), void *mmc) 74290293edSEsben Haabendal { 75290293edSEsben Haabendal struct of_mmc_spi *oms = to_of_mmc_spi(dev); 76290293edSEsben Haabendal 77290293edSEsben Haabendal return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 0, 78290293edSEsben Haabendal dev_name(dev), mmc); 79290293edSEsben Haabendal } 80290293edSEsben Haabendal 81290293edSEsben Haabendal static void of_mmc_spi_exit(struct device *dev, void *mmc) 82290293edSEsben Haabendal { 83290293edSEsben Haabendal struct of_mmc_spi *oms = to_of_mmc_spi(dev); 84290293edSEsben Haabendal 85290293edSEsben Haabendal free_irq(oms->detect_irq, mmc); 86290293edSEsben Haabendal } 87290293edSEsben Haabendal 889c43df57SAnton Vorontsov struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) 899c43df57SAnton Vorontsov { 909c43df57SAnton Vorontsov struct device *dev = &spi->dev; 9161c7a080SGrant Likely struct device_node *np = dev->of_node; 929c43df57SAnton Vorontsov struct of_mmc_spi *oms; 939c43df57SAnton Vorontsov const u32 *voltage_ranges; 949c43df57SAnton Vorontsov int num_ranges; 959c43df57SAnton Vorontsov int i; 969c43df57SAnton Vorontsov int ret = -EINVAL; 979c43df57SAnton Vorontsov 989c43df57SAnton Vorontsov if (dev->platform_data || !np) 999c43df57SAnton Vorontsov return dev->platform_data; 1009c43df57SAnton Vorontsov 1019c43df57SAnton Vorontsov oms = kzalloc(sizeof(*oms), GFP_KERNEL); 1029c43df57SAnton Vorontsov if (!oms) 1039c43df57SAnton Vorontsov return NULL; 1049c43df57SAnton Vorontsov 1059c43df57SAnton Vorontsov voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); 1069c43df57SAnton Vorontsov num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; 1079c43df57SAnton Vorontsov if (!voltage_ranges || !num_ranges) { 1089c43df57SAnton Vorontsov dev_err(dev, "OF: voltage-ranges unspecified\n"); 1099c43df57SAnton Vorontsov goto err_ocr; 1109c43df57SAnton Vorontsov } 1119c43df57SAnton Vorontsov 1129c43df57SAnton Vorontsov for (i = 0; i < num_ranges; i++) { 1139c43df57SAnton Vorontsov const int j = i * 2; 1149c43df57SAnton Vorontsov u32 mask; 1159c43df57SAnton Vorontsov 116b6bf30d9SJean-Christophe PLAGNIOL-VILLARD mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]), 117b6bf30d9SJean-Christophe PLAGNIOL-VILLARD be32_to_cpu(voltage_ranges[j + 1])); 1189c43df57SAnton Vorontsov if (!mask) { 1199c43df57SAnton Vorontsov ret = -EINVAL; 1209c43df57SAnton Vorontsov dev_err(dev, "OF: voltage-range #%d is invalid\n", i); 1219c43df57SAnton Vorontsov goto err_ocr; 1229c43df57SAnton Vorontsov } 1239c43df57SAnton Vorontsov oms->pdata.ocr_mask |= mask; 1249c43df57SAnton Vorontsov } 1259c43df57SAnton Vorontsov 1269c43df57SAnton Vorontsov for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) { 1279c43df57SAnton Vorontsov enum of_gpio_flags gpio_flags; 1289c43df57SAnton Vorontsov 1299c43df57SAnton Vorontsov oms->gpios[i] = of_get_gpio_flags(np, i, &gpio_flags); 1309c43df57SAnton Vorontsov if (!gpio_is_valid(oms->gpios[i])) 1319c43df57SAnton Vorontsov continue; 1329c43df57SAnton Vorontsov 13348f8151eSKay Sievers ret = gpio_request(oms->gpios[i], dev_name(dev)); 1349c43df57SAnton Vorontsov if (ret < 0) { 1359c43df57SAnton Vorontsov oms->gpios[i] = -EINVAL; 1369c43df57SAnton Vorontsov continue; 1379c43df57SAnton Vorontsov } 1389c43df57SAnton Vorontsov 1399c43df57SAnton Vorontsov if (gpio_flags & OF_GPIO_ACTIVE_LOW) 1409c43df57SAnton Vorontsov oms->alow_gpios[i] = true; 1419c43df57SAnton Vorontsov } 1429c43df57SAnton Vorontsov 1439c43df57SAnton Vorontsov if (gpio_is_valid(oms->gpios[CD_GPIO])) 1449c43df57SAnton Vorontsov oms->pdata.get_cd = of_mmc_spi_get_cd; 1459c43df57SAnton Vorontsov if (gpio_is_valid(oms->gpios[WP_GPIO])) 1469c43df57SAnton Vorontsov oms->pdata.get_ro = of_mmc_spi_get_ro; 1479c43df57SAnton Vorontsov 148290293edSEsben Haabendal oms->detect_irq = irq_of_parse_and_map(np, 0); 149073350f7SRoland Stigge if (oms->detect_irq != 0) { 150290293edSEsben Haabendal oms->pdata.init = of_mmc_spi_init; 151290293edSEsben Haabendal oms->pdata.exit = of_mmc_spi_exit; 152290293edSEsben Haabendal } else { 1539c43df57SAnton Vorontsov oms->pdata.caps |= MMC_CAP_NEEDS_POLL; 154290293edSEsben Haabendal } 1559c43df57SAnton Vorontsov 1569c43df57SAnton Vorontsov dev->platform_data = &oms->pdata; 1579c43df57SAnton Vorontsov return dev->platform_data; 1589c43df57SAnton Vorontsov err_ocr: 1599c43df57SAnton Vorontsov kfree(oms); 1609c43df57SAnton Vorontsov return NULL; 1619c43df57SAnton Vorontsov } 1629c43df57SAnton Vorontsov EXPORT_SYMBOL(mmc_spi_get_pdata); 1639c43df57SAnton Vorontsov 1649c43df57SAnton Vorontsov void mmc_spi_put_pdata(struct spi_device *spi) 1659c43df57SAnton Vorontsov { 1669c43df57SAnton Vorontsov struct device *dev = &spi->dev; 16761c7a080SGrant Likely struct device_node *np = dev->of_node; 1689c43df57SAnton Vorontsov struct of_mmc_spi *oms = to_of_mmc_spi(dev); 1699c43df57SAnton Vorontsov int i; 1709c43df57SAnton Vorontsov 1719c43df57SAnton Vorontsov if (!dev->platform_data || !np) 1729c43df57SAnton Vorontsov return; 1739c43df57SAnton Vorontsov 1749c43df57SAnton Vorontsov for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) { 1759c43df57SAnton Vorontsov if (gpio_is_valid(oms->gpios[i])) 1769c43df57SAnton Vorontsov gpio_free(oms->gpios[i]); 1779c43df57SAnton Vorontsov } 1789c43df57SAnton Vorontsov kfree(oms); 1799c43df57SAnton Vorontsov dev->platform_data = NULL; 1809c43df57SAnton Vorontsov } 1819c43df57SAnton Vorontsov EXPORT_SYMBOL(mmc_spi_put_pdata); 182