1aad5f19eSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0-or-later 29c43df57SAnton Vorontsov /* 39c43df57SAnton Vorontsov * OpenFirmware bindings for the MMC-over-SPI driver 49c43df57SAnton Vorontsov * 59c43df57SAnton Vorontsov * Copyright (c) MontaVista Software, Inc. 2008. 69c43df57SAnton Vorontsov * 79c43df57SAnton Vorontsov * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 89c43df57SAnton Vorontsov */ 99c43df57SAnton Vorontsov 109c43df57SAnton Vorontsov #include <linux/kernel.h> 119c43df57SAnton Vorontsov #include <linux/module.h> 129c43df57SAnton Vorontsov #include <linux/device.h> 135a0e3ad6STejun Heo #include <linux/slab.h> 14b2fce6adSDavid Miller #include <linux/irq.h> 159c43df57SAnton Vorontsov #include <linux/of.h> 16b2fce6adSDavid Miller #include <linux/of_irq.h> 179c43df57SAnton Vorontsov #include <linux/spi/spi.h> 189c43df57SAnton Vorontsov #include <linux/spi/mmc_spi.h> 199c43df57SAnton Vorontsov #include <linux/mmc/core.h> 209c43df57SAnton Vorontsov #include <linux/mmc/host.h> 219c43df57SAnton Vorontsov 22b9c350a0SWanlong Gao /* For archs that don't support NO_IRQ (such as mips), provide a dummy value */ 23b9c350a0SWanlong Gao #ifndef NO_IRQ 24b9c350a0SWanlong Gao #define NO_IRQ 0 25b9c350a0SWanlong Gao #endif 26b9c350a0SWanlong Gao 2702d9e58eSGrant Likely MODULE_LICENSE("GPL"); 2802d9e58eSGrant Likely 299c43df57SAnton Vorontsov struct of_mmc_spi { 30290293edSEsben Haabendal int detect_irq; 319c43df57SAnton Vorontsov struct mmc_spi_platform_data pdata; 329c43df57SAnton Vorontsov }; 339c43df57SAnton Vorontsov 349c43df57SAnton Vorontsov static struct of_mmc_spi *to_of_mmc_spi(struct device *dev) 359c43df57SAnton Vorontsov { 369c43df57SAnton Vorontsov return container_of(dev->platform_data, struct of_mmc_spi, pdata); 379c43df57SAnton Vorontsov } 389c43df57SAnton Vorontsov 39290293edSEsben Haabendal static int of_mmc_spi_init(struct device *dev, 40290293edSEsben Haabendal irqreturn_t (*irqhandler)(int, void *), void *mmc) 41290293edSEsben Haabendal { 42290293edSEsben Haabendal struct of_mmc_spi *oms = to_of_mmc_spi(dev); 43290293edSEsben Haabendal 4460b71f60Ssaurabh return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 4560b71f60Ssaurabh IRQF_ONESHOT, dev_name(dev), mmc); 46290293edSEsben Haabendal } 47290293edSEsben Haabendal 48290293edSEsben Haabendal static void of_mmc_spi_exit(struct device *dev, void *mmc) 49290293edSEsben Haabendal { 50290293edSEsben Haabendal struct of_mmc_spi *oms = to_of_mmc_spi(dev); 51290293edSEsben Haabendal 52290293edSEsben Haabendal free_irq(oms->detect_irq, mmc); 53290293edSEsben Haabendal } 54290293edSEsben Haabendal 559c43df57SAnton Vorontsov struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) 569c43df57SAnton Vorontsov { 576dab809bSAndy Shevchenko struct mmc_host *mmc = dev_get_drvdata(&spi->dev); 589c43df57SAnton Vorontsov struct device *dev = &spi->dev; 5961c7a080SGrant Likely struct device_node *np = dev->of_node; 609c43df57SAnton Vorontsov struct of_mmc_spi *oms; 619c43df57SAnton Vorontsov 629c43df57SAnton Vorontsov if (dev->platform_data || !np) 639c43df57SAnton Vorontsov return dev->platform_data; 649c43df57SAnton Vorontsov 659c43df57SAnton Vorontsov oms = kzalloc(sizeof(*oms), GFP_KERNEL); 669c43df57SAnton Vorontsov if (!oms) 679c43df57SAnton Vorontsov return NULL; 689c43df57SAnton Vorontsov 69*6c857ccfSAndy Shevchenko if (mmc_of_parse_voltage(mmc, &oms->pdata.ocr_mask) < 0) 709c43df57SAnton Vorontsov goto err_ocr; 719c43df57SAnton Vorontsov 72290293edSEsben Haabendal oms->detect_irq = irq_of_parse_and_map(np, 0); 73073350f7SRoland Stigge if (oms->detect_irq != 0) { 74290293edSEsben Haabendal oms->pdata.init = of_mmc_spi_init; 75290293edSEsben Haabendal oms->pdata.exit = of_mmc_spi_exit; 76290293edSEsben Haabendal } else { 779c43df57SAnton Vorontsov oms->pdata.caps |= MMC_CAP_NEEDS_POLL; 78290293edSEsben Haabendal } 799c43df57SAnton Vorontsov 809c43df57SAnton Vorontsov dev->platform_data = &oms->pdata; 819c43df57SAnton Vorontsov return dev->platform_data; 829c43df57SAnton Vorontsov err_ocr: 839c43df57SAnton Vorontsov kfree(oms); 849c43df57SAnton Vorontsov return NULL; 859c43df57SAnton Vorontsov } 869c43df57SAnton Vorontsov EXPORT_SYMBOL(mmc_spi_get_pdata); 879c43df57SAnton Vorontsov 889c43df57SAnton Vorontsov void mmc_spi_put_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 = to_of_mmc_spi(dev); 939c43df57SAnton Vorontsov 949c43df57SAnton Vorontsov if (!dev->platform_data || !np) 959c43df57SAnton Vorontsov return; 969c43df57SAnton Vorontsov 979c43df57SAnton Vorontsov kfree(oms); 989c43df57SAnton Vorontsov dev->platform_data = NULL; 999c43df57SAnton Vorontsov } 1009c43df57SAnton Vorontsov EXPORT_SYMBOL(mmc_spi_put_pdata); 101