1 /*
2 * linux-5.4/drivers/media/platform/sunxi-vin/vin-cci/sunxi_cci.c
3 *
4 * Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17
18 #include <linux/platform_device.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/slab.h>
22
23 #include "sunxi_cci.h"
24 #include "../platform/platform_cfg.h"
25
26 #if defined(CONFIG_CCI_MODULE) || defined(CONFIG_CCI) || defined(CONFIG_CCI_TO_TWI)
27 #define USED_TO_CCI_OR_TWI
28 #endif
29
30 #ifdef USED_TO_CCI_OR_TWI
31 #include "bsp_cci.h"
32
33 #define CCI_MODULE_NAME "vin_cci"
34
35 static LIST_HEAD(cci_drv_list);
36
cci_irq_handler(int this_irq,void * dev)37 static irqreturn_t cci_irq_handler(int this_irq, void *dev)
38 {
39 unsigned long flags = 0;
40 struct cci_dev *cci = (struct cci_dev *)dev;
41
42 spin_lock_irqsave(&cci->slock, flags);
43 bsp_cci_irq_process(cci->id);
44 spin_unlock_irqrestore(&cci->slock, flags);
45 return IRQ_HANDLED;
46 }
47
48
__cci_clk_get(struct cci_dev * dev)49 static int __cci_clk_get(struct cci_dev *dev)
50 {
51 #ifndef FPGA_VER
52 struct device_node *np = dev->pdev->dev.of_node;
53
54 dev->clock = of_clk_get(np, 0);
55 if (IS_ERR_OR_NULL(dev->clock))
56 vin_warn("cci get clk failed!\n");
57 #endif
58 return 0;
59 }
60
__cci_clk_enable(struct cci_dev * dev,int enable)61 static int __cci_clk_enable(struct cci_dev *dev, int enable)
62 {
63 #ifndef FPGA_VER
64 if (!IS_ERR_OR_NULL(dev->clock)) {
65 if (enable) {
66 if (clk_prepare_enable(dev->clock)) {
67 vin_err("cci clk enable error!\n");
68 return -1;
69 }
70 } else {
71 clk_disable_unprepare(dev->clock);
72 }
73 }
74 #endif
75 return 0;
76 }
77
__cci_clk_release(struct cci_dev * dev)78 static void __cci_clk_release(struct cci_dev *dev)
79 {
80 #ifndef FPGA_VER
81 if (dev->clock)
82 clk_put(dev->clock);
83 #endif
84 }
85
__cci_pin_config(struct cci_dev * dev,int enable)86 static int __cci_pin_config(struct cci_dev *dev, int enable)
87 {
88 #ifndef FPGA_VER
89 char pinctrl_names[10] = "";
90
91 if (!IS_ERR_OR_NULL(dev->pctrl))
92 devm_pinctrl_put(dev->pctrl);
93
94 if (enable)
95 strcpy(pinctrl_names, "default");
96 else
97 strcpy(pinctrl_names, "sleep");
98
99 dev->pctrl = devm_pinctrl_get_select(&dev->pdev->dev, pinctrl_names);
100 if (IS_ERR_OR_NULL(dev->pctrl)) {
101 vin_err("cci%d request pinctrl handle failed!\n", dev->id);
102 return -EINVAL;
103 }
104 usleep_range(1000, 1200);
105 #endif
106 return 0;
107 }
108
__cci_pin_release(struct cci_dev * dev)109 static int __cci_pin_release(struct cci_dev *dev)
110 {
111 #ifndef FPGA_VER
112 if (!IS_ERR_OR_NULL(dev->pctrl))
113 devm_pinctrl_put(dev->pctrl);
114 #endif
115 return 0;
116 }
117
cci_dev_get(int id)118 static struct cci_dev *cci_dev_get(int id)
119 {
120 struct cci_dev *cci;
121
122 list_for_each_entry(cci, &cci_drv_list, cci_list) {
123 if (cci->id == id)
124 return cci;
125 }
126 return NULL;
127 }
128
cci_s_power(unsigned int sel,int on_off)129 void cci_s_power(unsigned int sel, int on_off)
130 {
131 struct cci_dev *cci = cci_dev_get(sel);
132
133 if (cci == NULL) {
134 vin_err("cci is NULL!\n");
135 return;
136 }
137 vin_log(VIN_LOG_CCI, "%s, %d!\n", __func__, on_off);
138
139 if (on_off && (cci->use_cnt)++ > 0)
140 return;
141 else if (!on_off && (cci->use_cnt == 0 || --(cci->use_cnt) > 0))
142 return;
143
144 __cci_pin_config(cci, on_off);
145
146 if (on_off) {
147 __cci_clk_enable(cci, 1);
148 bsp_csi_cci_init_helper(sel);
149 } else {
150 bsp_csi_cci_exit(sel);
151 __cci_clk_enable(cci, 0);
152 }
153 }
154
155 #if defined(CONFIG_CCI_TO_TWI)
156 static int
sunxi_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)157 sunxi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
158 {
159 struct cci_dev *cci = (struct cci_dev *)adap->algo_data;
160 struct cci_msg cci_msg;
161 unsigned char *buf;
162 int i;
163 if (num == 1) { /*write*/
164 cci_msg.bus_fmt.saddr_7bit = msgs->addr;
165 cci_msg.bus_fmt.wr_flag = 0;
166 cci_msg.bus_fmt.rs_start = START_WITH_ID_W;
167 cci_msg.bus_fmt.rs_mode = STOP_START;
168 if (msgs->len == 0) {
169 cci_msg.bus_fmt.addr_len = 0;
170 cci_msg.bus_fmt.data_len = 0;
171 } else {
172 cci_msg.bus_fmt.addr_len = 1;
173 cci_msg.bus_fmt.data_len = msgs->len - 1;
174 }
175 cci_msg.pkt_buf = msgs->buf;
176 cci_msg.pkt_num = 1;
177
178 bsp_cci_tx_start_wait_done(cci->id, &cci_msg);
179 return 1;
180 } else if (num == 2) { /*read*/
181 buf = kzalloc(1 + msgs[1].len, GFP_KERNEL);
182 buf[0] = msgs[0].buf[0];
183 cci_msg.bus_fmt.saddr_7bit = msgs[0].addr;
184 cci_msg.bus_fmt.wr_flag = 1;
185 cci_msg.bus_fmt.rs_start = START_WITH_ID_W;
186 cci_msg.bus_fmt.rs_mode = STOP_START;
187 cci_msg.bus_fmt.addr_len = 1;
188 cci_msg.bus_fmt.data_len = msgs[1].len;
189 cci_msg.pkt_buf = buf;
190 cci_msg.pkt_num = 1;
191
192 bsp_cci_tx_start_wait_done(cci->id, &cci_msg);
193 for (i = 0; i < cci_msg.bus_fmt.data_len; i++)
194 msgs[1].buf[i] = buf[i+1];
195 kfree(buf);
196 return i;
197 }
198 }
199
sunxi_i2c_functionality(struct i2c_adapter * adap)200 static unsigned int sunxi_i2c_functionality(struct i2c_adapter *adap)
201 {
202 return I2C_FUNC_I2C|I2C_FUNC_10BIT_ADDR|I2C_FUNC_SMBUS_EMUL;
203 };
204
205 static const struct i2c_algorithm sunxi_i2c_algorithm = {
206 .master_xfer = sunxi_i2c_xfer,
207 .functionality = sunxi_i2c_functionality,
208 };
209 #endif
210
cci_probe(struct platform_device * pdev)211 static int cci_probe(struct platform_device *pdev)
212 {
213 struct device_node *np = pdev->dev.of_node;
214 struct cci_dev *cci = NULL;
215 int ret, irq = 0;
216
217 if (np == NULL) {
218 vin_err("CCI failed to get of node\n");
219 return -ENODEV;
220 }
221 cci = kzalloc(sizeof(struct cci_dev), GFP_KERNEL);
222 if (!cci) {
223 ret = -ENOMEM;
224 goto ekzalloc;
225 }
226
227 of_property_read_u32(np, "device_id", &pdev->id);
228 if (pdev->id < 0) {
229 vin_err("CCI failed to get device id\n");
230 ret = -EINVAL;
231 goto freedev;
232 }
233 cci->id = pdev->id;
234 cci->pdev = pdev;
235
236 irq = irq_of_parse_and_map(np, 0);
237 if (irq <= 0) {
238 vin_err("[CCI%d] failed to get irq\n", pdev->id);
239 ret = -EINVAL;
240 goto freedev;
241 }
242 cci->base = of_iomap(np, 0);
243 if (!cci->base) {
244 ret = -EIO;
245 goto freedev;
246 }
247 cci->irq = irq;
248 spin_lock_init(&cci->slock);
249
250 list_add_tail(&cci->cci_list, &cci_drv_list);
251 init_waitqueue_head(&cci->wait);
252
253 #if defined(CONFIG_CCI_TO_TWI)
254 cci->adap.owner = THIS_MODULE;
255 cci->adap.nr = cci->id + 4;
256 cci->adap.retries = 3;
257 cci->adap.timeout = 5*HZ;
258 cci->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
259 snprintf(cci->adap.name, sizeof(cci->adap.name),
260 "twi""%u", cci->adap.nr);
261 pdev->dev.init_name = cci->adap.name;
262
263 cci->adap.algo = &sunxi_i2c_algorithm;
264 #endif
265 ret = request_irq(irq, cci_irq_handler,
266 IRQF_SHARED, CCI_MODULE_NAME, cci);
267 if (ret) {
268 vin_err("[CCI%d] requeset irq failed!\n", cci->id);
269 goto unmap;
270 }
271 #if defined(CONFIG_CCI_TO_TWI)
272 cci->adap.algo_data = cci;
273 cci->adap.dev.parent = &pdev->dev;
274 cci->adap.dev.of_node = pdev->dev.of_node;
275
276 ret = i2c_add_numbered_adapter(&cci->adap);
277 if (ret < 0) {
278 vin_err("[i2c%d] failed to add adapter\n", cci->id);
279 }
280 #endif
281
282 ret = bsp_csi_cci_set_base_addr(cci->id, (unsigned long)cci->base);
283 if (ret < 0)
284 goto freeirq;
285
286 if (__cci_clk_get(cci)) {
287 vin_err("cci clock get failed!\n");
288 goto freeirq;
289 }
290 #if defined(CONFIG_CCI_TO_TWI)
291 cci_s_power(cci->id, 1);
292 #endif
293 platform_set_drvdata(pdev, cci);
294 vin_log(VIN_LOG_CCI, "cci probe end cci_sel = %d!\n", cci->id);
295
296 return 0;
297 freeirq:
298 free_irq(irq, cci);
299 unmap:
300 iounmap(cci->base);
301 freedev:
302 kfree(cci);
303 ekzalloc:
304 vin_err("cci probe err!\n");
305 return ret;
306 }
307
cci_remove(struct platform_device * pdev)308 static int cci_remove(struct platform_device *pdev)
309 {
310 struct cci_dev *cci = platform_get_drvdata(pdev);
311
312 platform_set_drvdata(pdev, NULL);
313
314 __cci_pin_release(cci);
315 __cci_clk_release(cci);
316 free_irq(cci->irq, cci);
317 if (cci->base)
318 iounmap(cci->base);
319 list_del(&cci->cci_list);
320 kfree(cci);
321 return 0;
322 }
323
324 static const struct of_device_id sunxi_cci_match[] = {
325 {.compatible = "allwinner,sunxi-csi_cci",},
326 {},
327 };
328
329 MODULE_DEVICE_TABLE(of, sunxi_cci_match);
330
331 static struct platform_driver cci_platform_driver = {
332 .probe = cci_probe,
333 .remove = cci_remove,
334 .driver = {
335 .name = CCI_MODULE_NAME,
336 .owner = THIS_MODULE,
337 .of_match_table = sunxi_cci_match,
338 },
339 };
340
341 #endif
342
sunxi_cci_platform_register(void)343 int sunxi_cci_platform_register(void)
344 {
345 #ifdef USED_TO_CCI_OR_TWI
346 int ret;
347
348 ret = platform_driver_register(&cci_platform_driver);
349 if (ret) {
350 vin_err("platform driver register failed\n");
351 return ret;
352 }
353 vin_log(VIN_LOG_CCI, "cci_init end\n");
354 #endif
355 return 0;
356 }
357
sunxi_cci_platform_unregister(void)358 void sunxi_cci_platform_unregister(void)
359 {
360 #ifdef USED_TO_CCI_OR_TWI
361 platform_driver_unregister(&cci_platform_driver);
362 vin_log(VIN_LOG_CCI, "cci_exit end\n");
363 #endif
364 }
365
366