Merge tag 'amd-drm-fixes-5.11-2020-12-16' of git://people.freedesktop.org/~agd5f...
[linux-2.6-microblaze.git] / sound / soc / codecs / l3.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * L3 code
4  *
5  *  Copyright (C) 2008, Christian Pellegrin <chripell@evolware.org>
6  *
7  * based on:
8  *
9  * L3 bus algorithm module.
10  *
11  *  Copyright (C) 2001 Russell King, All Rights Reserved.
12  */
13
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/delay.h>
17 #include <linux/device.h>
18 #include <linux/gpio.h>
19
20 #include <sound/l3.h>
21
22 /*
23  * Send one byte of data to the chip.  Data is latched into the chip on
24  * the rising edge of the clock.
25  */
26 static void sendbyte(struct l3_pins *adap, unsigned int byte)
27 {
28         int i;
29
30         for (i = 0; i < 8; i++) {
31                 adap->setclk(adap, 0);
32                 udelay(adap->data_hold);
33                 adap->setdat(adap, byte & 1);
34                 udelay(adap->data_setup);
35                 adap->setclk(adap, 1);
36                 udelay(adap->clock_high);
37                 byte >>= 1;
38         }
39 }
40
41 /*
42  * Send a set of bytes to the chip.  We need to pulse the MODE line
43  * between each byte, but never at the start nor at the end of the
44  * transfer.
45  */
46 static void sendbytes(struct l3_pins *adap, const u8 *buf,
47                       int len)
48 {
49         int i;
50
51         for (i = 0; i < len; i++) {
52                 if (i) {
53                         udelay(adap->mode_hold);
54                         adap->setmode(adap, 0);
55                         udelay(adap->mode);
56                 }
57                 adap->setmode(adap, 1);
58                 udelay(adap->mode_setup);
59                 sendbyte(adap, buf[i]);
60         }
61 }
62
63 int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
64 {
65         adap->setclk(adap, 1);
66         adap->setdat(adap, 1);
67         adap->setmode(adap, 1);
68         udelay(adap->mode);
69
70         adap->setmode(adap, 0);
71         udelay(adap->mode_setup);
72         sendbyte(adap, addr);
73         udelay(adap->mode_hold);
74
75         sendbytes(adap, data, len);
76
77         adap->setclk(adap, 1);
78         adap->setdat(adap, 1);
79         adap->setmode(adap, 0);
80
81         return len;
82 }
83 EXPORT_SYMBOL_GPL(l3_write);
84
85
86 static void l3_set_clk(struct l3_pins *adap, int val)
87 {
88         gpio_set_value(adap->gpio_clk, val);
89 }
90
91 static void l3_set_data(struct l3_pins *adap, int val)
92 {
93         gpio_set_value(adap->gpio_data, val);
94 }
95
96 static void l3_set_mode(struct l3_pins *adap, int val)
97 {
98         gpio_set_value(adap->gpio_mode, val);
99 }
100
101 int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap)
102 {
103         int ret;
104
105         if (!adap->use_gpios)
106                 return -EINVAL;
107
108         ret = devm_gpio_request_one(dev, adap->gpio_data,
109                                 GPIOF_OUT_INIT_LOW, "l3_data");
110         if (ret < 0)
111                 return ret;
112         adap->setdat = l3_set_data;
113
114         ret = devm_gpio_request_one(dev, adap->gpio_clk,
115                                 GPIOF_OUT_INIT_LOW, "l3_clk");
116         if (ret < 0)
117                 return ret;
118         adap->setclk = l3_set_clk;
119
120         ret = devm_gpio_request_one(dev, adap->gpio_mode,
121                                 GPIOF_OUT_INIT_LOW, "l3_mode");
122         if (ret < 0)
123                 return ret;
124         adap->setmode = l3_set_mode;
125
126         return 0;
127 }
128 EXPORT_SYMBOL_GPL(l3_set_gpio_ops);
129
130 MODULE_DESCRIPTION("L3 bit-banging driver");
131 MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
132 MODULE_LICENSE("GPL");