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 struct nvmem_config nvmem; 38 }; 39 40 static int imx_iim_read(void *context, unsigned int offset, 41 void *buf, size_t bytes) 42 { 43 struct iim_priv *iim = context; 44 int i, ret; 45 u8 *buf8 = buf; 46 47 ret = clk_prepare_enable(iim->clk); 48 if (ret) 49 return ret; 50 51 for (i = offset; i < offset + bytes; i++) { 52 int bank = i >> 5; 53 int reg = i & 0x1f; 54 55 *buf8++ = readl(iim->base + IIM_BANK_BASE(bank) + reg * 4); 56 } 57 58 clk_disable_unprepare(iim->clk); 59 60 return 0; 61 } 62 63 static struct imx_iim_drvdata imx27_drvdata = { 64 .nregs = 2 * 32, 65 }; 66 67 static struct imx_iim_drvdata imx25_imx31_imx35_drvdata = { 68 .nregs = 3 * 32, 69 }; 70 71 static struct imx_iim_drvdata imx51_drvdata = { 72 .nregs = 4 * 32, 73 }; 74 75 static struct imx_iim_drvdata imx53_drvdata = { 76 .nregs = 4 * 32 + 16, 77 }; 78 79 static const struct of_device_id imx_iim_dt_ids[] = { 80 { 81 .compatible = "fsl,imx25-iim", 82 .data = &imx25_imx31_imx35_drvdata, 83 }, { 84 .compatible = "fsl,imx27-iim", 85 .data = &imx27_drvdata, 86 }, { 87 .compatible = "fsl,imx31-iim", 88 .data = &imx25_imx31_imx35_drvdata, 89 }, { 90 .compatible = "fsl,imx35-iim", 91 .data = &imx25_imx31_imx35_drvdata, 92 }, { 93 .compatible = "fsl,imx51-iim", 94 .data = &imx51_drvdata, 95 }, { 96 .compatible = "fsl,imx53-iim", 97 .data = &imx53_drvdata, 98 }, { 99 /* sentinel */ 100 }, 101 }; 102 MODULE_DEVICE_TABLE(of, imx_iim_dt_ids); 103 104 static int imx_iim_probe(struct platform_device *pdev) 105 { 106 const struct of_device_id *of_id; 107 struct device *dev = &pdev->dev; 108 struct resource *res; 109 struct iim_priv *iim; 110 struct nvmem_device *nvmem; 111 struct nvmem_config *cfg; 112 const struct imx_iim_drvdata *drvdata = NULL; 113 114 iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL); 115 if (!iim) 116 return -ENOMEM; 117 118 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 119 iim->base = devm_ioremap_resource(dev, res); 120 if (IS_ERR(iim->base)) 121 return PTR_ERR(iim->base); 122 123 of_id = of_match_device(imx_iim_dt_ids, dev); 124 if (!of_id) 125 return -ENODEV; 126 127 drvdata = of_id->data; 128 129 iim->clk = devm_clk_get(&pdev->dev, NULL); 130 if (IS_ERR(iim->clk)) 131 return PTR_ERR(iim->clk); 132 133 cfg = &iim->nvmem; 134 135 cfg->name = "imx-iim", 136 cfg->read_only = true, 137 cfg->word_size = 1, 138 cfg->stride = 1, 139 cfg->owner = THIS_MODULE, 140 cfg->reg_read = imx_iim_read, 141 cfg->dev = dev; 142 cfg->size = drvdata->nregs; 143 cfg->priv = iim; 144 145 nvmem = nvmem_register(cfg); 146 if (IS_ERR(nvmem)) 147 return PTR_ERR(nvmem); 148 149 platform_set_drvdata(pdev, nvmem); 150 151 return 0; 152 } 153 154 static int imx_iim_remove(struct platform_device *pdev) 155 { 156 struct nvmem_device *nvmem = platform_get_drvdata(pdev); 157 158 return nvmem_unregister(nvmem); 159 } 160 161 static struct platform_driver imx_iim_driver = { 162 .probe = imx_iim_probe, 163 .remove = imx_iim_remove, 164 .driver = { 165 .name = "imx-iim", 166 .of_match_table = imx_iim_dt_ids, 167 }, 168 }; 169 module_platform_driver(imx_iim_driver); 170 171 MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>"); 172 MODULE_DESCRIPTION("i.MX IIM driver"); 173 MODULE_LICENSE("GPL v2"); 174