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 iim_priv *iim; 108 struct nvmem_device *nvmem; 109 struct nvmem_config cfg = {}; 110 const struct imx_iim_drvdata *drvdata = NULL; 111 112 iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL); 113 if (!iim) 114 return -ENOMEM; 115 116 iim->base = devm_platform_ioremap_resource(pdev, 0); 117 if (IS_ERR(iim->base)) 118 return PTR_ERR(iim->base); 119 120 of_id = of_match_device(imx_iim_dt_ids, dev); 121 if (!of_id) 122 return -ENODEV; 123 124 drvdata = of_id->data; 125 126 iim->clk = devm_clk_get(dev, NULL); 127 if (IS_ERR(iim->clk)) 128 return PTR_ERR(iim->clk); 129 130 cfg.name = "imx-iim", 131 cfg.read_only = true, 132 cfg.word_size = 1, 133 cfg.stride = 1, 134 cfg.reg_read = imx_iim_read, 135 cfg.dev = dev; 136 cfg.size = drvdata->nregs; 137 cfg.priv = iim; 138 139 nvmem = devm_nvmem_register(dev, &cfg); 140 141 return PTR_ERR_OR_ZERO(nvmem); 142 } 143 144 static struct platform_driver imx_iim_driver = { 145 .probe = imx_iim_probe, 146 .driver = { 147 .name = "imx-iim", 148 .of_match_table = imx_iim_dt_ids, 149 }, 150 }; 151 module_platform_driver(imx_iim_driver); 152 153 MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>"); 154 MODULE_DESCRIPTION("i.MX IIM driver"); 155 MODULE_LICENSE("GPL v2"); 156