Commit | Line | Data |
---|---|---|
c066c1c0 MG |
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"); |