1 /* 2 * i.MX IIM driver 3 * 4 * Copyright (c) 2017 Pengutronix, Michael Grzeschik <m.grzeschik@pengutronix.de> 5 * 6 * Based on the barebox iim driver, 7 * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>, 8 * Orex Computed Radiography 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 12 * as published by the Free Software Foundation. 13 * 14 * http://www.opensource.org/licenses/gpl-license.html 15 * http://www.gnu.org/copyleft/gpl.html 16 */ 17 18 #include <linux/device.h> 19 #include <linux/io.h> 20 #include <linux/module.h> 21 #include <linux/nvmem-provider.h> 22 #include <linux/of.h> 23 #include <linux/of_device.h> 24 #include <linux/platform_device.h> 25 #include <linux/slab.h> 26 #include <linux/clk.h> 27 28 #define IIM_BANK_BASE(n) (0x800 + 0x400 * (n)) 29 30 struct imx_iim_drvdata { 31 unsigned int nregs; 32 }; 33 34 struct iim_priv { 35 void __iomem *base; 36 struct clk *clk; 37 }; 38 39 static int imx_iim_read(void *context, unsigned int offset, 40 void *buf, size_t bytes) 41 { 42 struct iim_priv *iim = context; 43 int i, ret; 44 u8 *buf8 = buf; 45 46 ret = clk_prepare_enable(iim->clk); 47 if (ret) 48 return ret; 49 50 for (i = offset; i < offset + bytes; i++) { 51 int bank = i >> 5; 52 int reg = i & 0x1f; 53 54 *buf8++ = readl(iim->base + IIM_BANK_BASE(bank) + reg * 4); 55 } 56 57 clk_disable_unprepare(iim->clk); 58 59 return 0; 60 } 61 62 static struct imx_iim_drvdata imx27_drvdata = { 63 .nregs = 2 * 32, 64 }; 65 66 static struct imx_iim_drvdata imx25_imx31_imx35_drvdata = { 67 .nregs = 3 * 32, 68 }; 69 70 static struct imx_iim_drvdata imx51_drvdata = { 71 .nregs = 4 * 32, 72 }; 73 74 static struct imx_iim_drvdata imx53_drvdata = { 75 .nregs = 4 * 32 + 16, 76 }; 77 78 static const struct of_device_id imx_iim_dt_ids[] = { 79 { 80 .compatible = "fsl,imx25-iim", 81 .data = &imx25_imx31_imx35_drvdata, 82 }, { 83 .compatible = "fsl,imx27-iim", 84 .data = &imx27_drvdata, 85 }, { 86 .compatible = "fsl,imx31-iim", 87 .data = &imx25_imx31_imx35_drvdata, 88 }, { 89 .compatible = "fsl,imx35-iim", 90 .data = &imx25_imx31_imx35_drvdata, 91 }, { 92 .compatible = "fsl,imx51-iim", 93 .data = &imx51_drvdata, 94 }, { 95 .compatible = "fsl,imx53-iim", 96 .data = &imx53_drvdata, 97 }, { 98 /* sentinel */ 99 }, 100 }; 101 MODULE_DEVICE_TABLE(of, imx_iim_dt_ids); 102 103 static int imx_iim_probe(struct platform_device *pdev) 104 { 105 const struct of_device_id *of_id; 106 struct device *dev = &pdev->dev; 107 struct resource *res; 108 struct iim_priv *iim; 109 struct nvmem_device *nvmem; 110 struct nvmem_config cfg = {}; 111 const struct imx_iim_drvdata *drvdata = NULL; 112 113 iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL); 114 if (!iim) 115 return -ENOMEM; 116 117 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 118 iim->base = devm_ioremap_resource(dev, res); 119 if (IS_ERR(iim->base)) 120 return PTR_ERR(iim->base); 121 122 of_id = of_match_device(imx_iim_dt_ids, dev); 123 if (!of_id) 124 return -ENODEV; 125 126 drvdata = of_id->data; 127 128 iim->clk = devm_clk_get(dev, NULL); 129 if (IS_ERR(iim->clk)) 130 return PTR_ERR(iim->clk); 131 132 cfg.name = "imx-iim", 133 cfg.read_only = true, 134 cfg.word_size = 1, 135 cfg.stride = 1, 136 cfg.reg_read = imx_iim_read, 137 cfg.dev = dev; 138 cfg.size = drvdata->nregs; 139 cfg.priv = iim; 140 141 nvmem = devm_nvmem_register(dev, &cfg); 142 143 return PTR_ERR_OR_ZERO(nvmem); 144 } 145 146 static struct platform_driver imx_iim_driver = { 147 .probe = imx_iim_probe, 148 .driver = { 149 .name = "imx-iim", 150 .of_match_table = imx_iim_dt_ids, 151 }, 152 }; 153 module_platform_driver(imx_iim_driver); 154 155 MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>"); 156 MODULE_DESCRIPTION("i.MX IIM driver"); 157 MODULE_LICENSE("GPL v2"); 158