1*acee2e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c066c1c0SMichael Grzeschik /* 3c066c1c0SMichael Grzeschik * i.MX IIM driver 4c066c1c0SMichael Grzeschik * 5c066c1c0SMichael Grzeschik * Copyright (c) 2017 Pengutronix, Michael Grzeschik <m.grzeschik@pengutronix.de> 6c066c1c0SMichael Grzeschik * 7c066c1c0SMichael Grzeschik * Based on the barebox iim driver, 8c066c1c0SMichael Grzeschik * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>, 9c066c1c0SMichael Grzeschik * Orex Computed Radiography 10c066c1c0SMichael Grzeschik */ 11c066c1c0SMichael Grzeschik 12c066c1c0SMichael Grzeschik #include <linux/device.h> 13c066c1c0SMichael Grzeschik #include <linux/io.h> 14c066c1c0SMichael Grzeschik #include <linux/module.h> 15c066c1c0SMichael Grzeschik #include <linux/nvmem-provider.h> 16c066c1c0SMichael Grzeschik #include <linux/of.h> 17c066c1c0SMichael Grzeschik #include <linux/of_device.h> 18c066c1c0SMichael Grzeschik #include <linux/platform_device.h> 19c066c1c0SMichael Grzeschik #include <linux/slab.h> 20c066c1c0SMichael Grzeschik #include <linux/clk.h> 21c066c1c0SMichael Grzeschik 22c066c1c0SMichael Grzeschik #define IIM_BANK_BASE(n) (0x800 + 0x400 * (n)) 23c066c1c0SMichael Grzeschik 24c066c1c0SMichael Grzeschik struct imx_iim_drvdata { 25c066c1c0SMichael Grzeschik unsigned int nregs; 26c066c1c0SMichael Grzeschik }; 27c066c1c0SMichael Grzeschik 28c066c1c0SMichael Grzeschik struct iim_priv { 29c066c1c0SMichael Grzeschik void __iomem *base; 30c066c1c0SMichael Grzeschik struct clk *clk; 31c066c1c0SMichael Grzeschik }; 32c066c1c0SMichael Grzeschik 33c066c1c0SMichael Grzeschik static int imx_iim_read(void *context, unsigned int offset, 34c066c1c0SMichael Grzeschik void *buf, size_t bytes) 35c066c1c0SMichael Grzeschik { 36c066c1c0SMichael Grzeschik struct iim_priv *iim = context; 37c066c1c0SMichael Grzeschik int i, ret; 38c066c1c0SMichael Grzeschik u8 *buf8 = buf; 39c066c1c0SMichael Grzeschik 40c066c1c0SMichael Grzeschik ret = clk_prepare_enable(iim->clk); 41c066c1c0SMichael Grzeschik if (ret) 42c066c1c0SMichael Grzeschik return ret; 43c066c1c0SMichael Grzeschik 44c066c1c0SMichael Grzeschik for (i = offset; i < offset + bytes; i++) { 45c066c1c0SMichael Grzeschik int bank = i >> 5; 46c066c1c0SMichael Grzeschik int reg = i & 0x1f; 47c066c1c0SMichael Grzeschik 48c066c1c0SMichael Grzeschik *buf8++ = readl(iim->base + IIM_BANK_BASE(bank) + reg * 4); 49c066c1c0SMichael Grzeschik } 50c066c1c0SMichael Grzeschik 51c066c1c0SMichael Grzeschik clk_disable_unprepare(iim->clk); 52c066c1c0SMichael Grzeschik 53c066c1c0SMichael Grzeschik return 0; 54c066c1c0SMichael Grzeschik } 55c066c1c0SMichael Grzeschik 56c066c1c0SMichael Grzeschik static struct imx_iim_drvdata imx27_drvdata = { 57c066c1c0SMichael Grzeschik .nregs = 2 * 32, 58c066c1c0SMichael Grzeschik }; 59c066c1c0SMichael Grzeschik 60c066c1c0SMichael Grzeschik static struct imx_iim_drvdata imx25_imx31_imx35_drvdata = { 61c066c1c0SMichael Grzeschik .nregs = 3 * 32, 62c066c1c0SMichael Grzeschik }; 63c066c1c0SMichael Grzeschik 64c066c1c0SMichael Grzeschik static struct imx_iim_drvdata imx51_drvdata = { 65c066c1c0SMichael Grzeschik .nregs = 4 * 32, 66c066c1c0SMichael Grzeschik }; 67c066c1c0SMichael Grzeschik 68c066c1c0SMichael Grzeschik static struct imx_iim_drvdata imx53_drvdata = { 69c066c1c0SMichael Grzeschik .nregs = 4 * 32 + 16, 70c066c1c0SMichael Grzeschik }; 71c066c1c0SMichael Grzeschik 72c066c1c0SMichael Grzeschik static const struct of_device_id imx_iim_dt_ids[] = { 73c066c1c0SMichael Grzeschik { 74c066c1c0SMichael Grzeschik .compatible = "fsl,imx25-iim", 75c066c1c0SMichael Grzeschik .data = &imx25_imx31_imx35_drvdata, 76c066c1c0SMichael Grzeschik }, { 77c066c1c0SMichael Grzeschik .compatible = "fsl,imx27-iim", 78c066c1c0SMichael Grzeschik .data = &imx27_drvdata, 79c066c1c0SMichael Grzeschik }, { 80c066c1c0SMichael Grzeschik .compatible = "fsl,imx31-iim", 81c066c1c0SMichael Grzeschik .data = &imx25_imx31_imx35_drvdata, 82c066c1c0SMichael Grzeschik }, { 83c066c1c0SMichael Grzeschik .compatible = "fsl,imx35-iim", 84c066c1c0SMichael Grzeschik .data = &imx25_imx31_imx35_drvdata, 85c066c1c0SMichael Grzeschik }, { 86c066c1c0SMichael Grzeschik .compatible = "fsl,imx51-iim", 87c066c1c0SMichael Grzeschik .data = &imx51_drvdata, 88c066c1c0SMichael Grzeschik }, { 89c066c1c0SMichael Grzeschik .compatible = "fsl,imx53-iim", 90c066c1c0SMichael Grzeschik .data = &imx53_drvdata, 91c066c1c0SMichael Grzeschik }, { 92c066c1c0SMichael Grzeschik /* sentinel */ 93c066c1c0SMichael Grzeschik }, 94c066c1c0SMichael Grzeschik }; 95c066c1c0SMichael Grzeschik MODULE_DEVICE_TABLE(of, imx_iim_dt_ids); 96c066c1c0SMichael Grzeschik 97c066c1c0SMichael Grzeschik static int imx_iim_probe(struct platform_device *pdev) 98c066c1c0SMichael Grzeschik { 99c066c1c0SMichael Grzeschik const struct of_device_id *of_id; 100c066c1c0SMichael Grzeschik struct device *dev = &pdev->dev; 101c066c1c0SMichael Grzeschik struct iim_priv *iim; 102c066c1c0SMichael Grzeschik struct nvmem_device *nvmem; 10301d35cabSMasahiro Yamada struct nvmem_config cfg = {}; 104c066c1c0SMichael Grzeschik const struct imx_iim_drvdata *drvdata = NULL; 105c066c1c0SMichael Grzeschik 106c066c1c0SMichael Grzeschik iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL); 107c066c1c0SMichael Grzeschik if (!iim) 108c066c1c0SMichael Grzeschik return -ENOMEM; 109c066c1c0SMichael Grzeschik 110ededa045SAnson Huang iim->base = devm_platform_ioremap_resource(pdev, 0); 111c066c1c0SMichael Grzeschik if (IS_ERR(iim->base)) 112c066c1c0SMichael Grzeschik return PTR_ERR(iim->base); 113c066c1c0SMichael Grzeschik 114c066c1c0SMichael Grzeschik of_id = of_match_device(imx_iim_dt_ids, dev); 115c066c1c0SMichael Grzeschik if (!of_id) 116c066c1c0SMichael Grzeschik return -ENODEV; 117c066c1c0SMichael Grzeschik 118c066c1c0SMichael Grzeschik drvdata = of_id->data; 119c066c1c0SMichael Grzeschik 120b28b7381SAndrey Smirnov iim->clk = devm_clk_get(dev, NULL); 121c066c1c0SMichael Grzeschik if (IS_ERR(iim->clk)) 122c066c1c0SMichael Grzeschik return PTR_ERR(iim->clk); 123c066c1c0SMichael Grzeschik 12401d35cabSMasahiro Yamada cfg.name = "imx-iim", 12501d35cabSMasahiro Yamada cfg.read_only = true, 12601d35cabSMasahiro Yamada cfg.word_size = 1, 12701d35cabSMasahiro Yamada cfg.stride = 1, 12801d35cabSMasahiro Yamada cfg.reg_read = imx_iim_read, 12901d35cabSMasahiro Yamada cfg.dev = dev; 13001d35cabSMasahiro Yamada cfg.size = drvdata->nregs; 13101d35cabSMasahiro Yamada cfg.priv = iim; 132c066c1c0SMichael Grzeschik 133547a2c9bSAndrey Smirnov nvmem = devm_nvmem_register(dev, &cfg); 134c066c1c0SMichael Grzeschik 135547a2c9bSAndrey Smirnov return PTR_ERR_OR_ZERO(nvmem); 136c066c1c0SMichael Grzeschik } 137c066c1c0SMichael Grzeschik 138c066c1c0SMichael Grzeschik static struct platform_driver imx_iim_driver = { 139c066c1c0SMichael Grzeschik .probe = imx_iim_probe, 140c066c1c0SMichael Grzeschik .driver = { 141c066c1c0SMichael Grzeschik .name = "imx-iim", 142c066c1c0SMichael Grzeschik .of_match_table = imx_iim_dt_ids, 143c066c1c0SMichael Grzeschik }, 144c066c1c0SMichael Grzeschik }; 145c066c1c0SMichael Grzeschik module_platform_driver(imx_iim_driver); 146c066c1c0SMichael Grzeschik 147c066c1c0SMichael Grzeschik MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>"); 148c066c1c0SMichael Grzeschik MODULE_DESCRIPTION("i.MX IIM driver"); 149c066c1c0SMichael Grzeschik MODULE_LICENSE("GPL v2"); 150