xref: /openbmc/linux/drivers/nvmem/imx-iim.c (revision 9d64fc08)
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