1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Samsung LSI S5C73M3 8M pixel camera driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
6*4882a593Smuzhiyun * Sylwester Nawrocki <s.nawrocki@samsung.com>
7*4882a593Smuzhiyun * Andrzej Hajda <a.hajda@samsung.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/sizes.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/media.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/spi/spi.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "s5c73m3.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static const struct of_device_id s5c73m3_spi_ids[] = {
23*4882a593Smuzhiyun { .compatible = "samsung,s5c73m3" },
24*4882a593Smuzhiyun { }
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, s5c73m3_spi_ids);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun enum spi_direction {
29*4882a593Smuzhiyun SPI_DIR_RX,
30*4882a593Smuzhiyun SPI_DIR_TX
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
spi_xmit(struct spi_device * spi_dev,void * addr,const int len,enum spi_direction dir)33*4882a593Smuzhiyun static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len,
34*4882a593Smuzhiyun enum spi_direction dir)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun struct spi_message msg;
37*4882a593Smuzhiyun int r;
38*4882a593Smuzhiyun struct spi_transfer xfer = {
39*4882a593Smuzhiyun .len = len,
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun if (dir == SPI_DIR_TX)
43*4882a593Smuzhiyun xfer.tx_buf = addr;
44*4882a593Smuzhiyun else
45*4882a593Smuzhiyun xfer.rx_buf = addr;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun if (spi_dev == NULL) {
48*4882a593Smuzhiyun pr_err("SPI device is uninitialized\n");
49*4882a593Smuzhiyun return -ENODEV;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun spi_message_init(&msg);
53*4882a593Smuzhiyun spi_message_add_tail(&xfer, &msg);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun r = spi_sync(spi_dev, &msg);
56*4882a593Smuzhiyun if (r < 0)
57*4882a593Smuzhiyun dev_err(&spi_dev->dev, "%s spi_sync failed %d\n", __func__, r);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun return r;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
s5c73m3_spi_write(struct s5c73m3 * state,const void * addr,const unsigned int len,const unsigned int tx_size)62*4882a593Smuzhiyun int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr,
63*4882a593Smuzhiyun const unsigned int len, const unsigned int tx_size)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun struct spi_device *spi_dev = state->spi_dev;
66*4882a593Smuzhiyun u32 count = len / tx_size;
67*4882a593Smuzhiyun u32 extra = len % tx_size;
68*4882a593Smuzhiyun unsigned int i, j = 0;
69*4882a593Smuzhiyun u8 padding[32];
70*4882a593Smuzhiyun int r = 0;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun memset(padding, 0, sizeof(padding));
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun for (i = 0; i < count; i++) {
75*4882a593Smuzhiyun r = spi_xmit(spi_dev, (void *)addr + j, tx_size, SPI_DIR_TX);
76*4882a593Smuzhiyun if (r < 0)
77*4882a593Smuzhiyun return r;
78*4882a593Smuzhiyun j += tx_size;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (extra > 0) {
82*4882a593Smuzhiyun r = spi_xmit(spi_dev, (void *)addr + j, extra, SPI_DIR_TX);
83*4882a593Smuzhiyun if (r < 0)
84*4882a593Smuzhiyun return r;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun return spi_xmit(spi_dev, padding, sizeof(padding), SPI_DIR_TX);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
s5c73m3_spi_read(struct s5c73m3 * state,void * addr,const unsigned int len,const unsigned int tx_size)90*4882a593Smuzhiyun int s5c73m3_spi_read(struct s5c73m3 *state, void *addr,
91*4882a593Smuzhiyun const unsigned int len, const unsigned int tx_size)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun struct spi_device *spi_dev = state->spi_dev;
94*4882a593Smuzhiyun u32 count = len / tx_size;
95*4882a593Smuzhiyun u32 extra = len % tx_size;
96*4882a593Smuzhiyun unsigned int i, j = 0;
97*4882a593Smuzhiyun int r = 0;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun for (i = 0; i < count; i++) {
100*4882a593Smuzhiyun r = spi_xmit(spi_dev, addr + j, tx_size, SPI_DIR_RX);
101*4882a593Smuzhiyun if (r < 0)
102*4882a593Smuzhiyun return r;
103*4882a593Smuzhiyun j += tx_size;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (extra > 0)
107*4882a593Smuzhiyun return spi_xmit(spi_dev, addr + j, extra, SPI_DIR_RX);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
s5c73m3_spi_probe(struct spi_device * spi)112*4882a593Smuzhiyun static int s5c73m3_spi_probe(struct spi_device *spi)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun int r;
115*4882a593Smuzhiyun struct s5c73m3 *state = container_of(spi->dev.driver, struct s5c73m3,
116*4882a593Smuzhiyun spidrv.driver);
117*4882a593Smuzhiyun spi->bits_per_word = 32;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun r = spi_setup(spi);
120*4882a593Smuzhiyun if (r < 0) {
121*4882a593Smuzhiyun dev_err(&spi->dev, "spi_setup() failed\n");
122*4882a593Smuzhiyun return r;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun mutex_lock(&state->lock);
126*4882a593Smuzhiyun state->spi_dev = spi;
127*4882a593Smuzhiyun mutex_unlock(&state->lock);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun v4l2_info(&state->sensor_sd, "S5C73M3 SPI probed successfully\n");
130*4882a593Smuzhiyun return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
s5c73m3_spi_remove(struct spi_device * spi)133*4882a593Smuzhiyun static int s5c73m3_spi_remove(struct spi_device *spi)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
s5c73m3_register_spi_driver(struct s5c73m3 * state)138*4882a593Smuzhiyun int s5c73m3_register_spi_driver(struct s5c73m3 *state)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct spi_driver *spidrv = &state->spidrv;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun spidrv->remove = s5c73m3_spi_remove;
143*4882a593Smuzhiyun spidrv->probe = s5c73m3_spi_probe;
144*4882a593Smuzhiyun spidrv->driver.name = S5C73M3_SPI_DRV_NAME;
145*4882a593Smuzhiyun spidrv->driver.of_match_table = s5c73m3_spi_ids;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun return spi_register_driver(spidrv);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
s5c73m3_unregister_spi_driver(struct s5c73m3 * state)150*4882a593Smuzhiyun void s5c73m3_unregister_spi_driver(struct s5c73m3 *state)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun spi_unregister_driver(&state->spidrv);
153*4882a593Smuzhiyun }
154