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  */
sendbyte(struct l3_pins * adap,unsigned int byte)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  */
sendbytes(struct l3_pins * adap,const u8 * buf,int len)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 
l3_write(struct l3_pins * adap,u8 addr,u8 * data,int len)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 
l3_set_clk(struct l3_pins * adap,int val)86 static void l3_set_clk(struct l3_pins *adap, int val)
87 {
88 	gpio_set_value(adap->gpio_clk, val);
89 }
90 
l3_set_data(struct l3_pins * adap,int val)91 static void l3_set_data(struct l3_pins *adap, int val)
92 {
93 	gpio_set_value(adap->gpio_data, val);
94 }
95 
l3_set_mode(struct l3_pins * adap,int val)96 static void l3_set_mode(struct l3_pins *adap, int val)
97 {
98 	gpio_set_value(adap->gpio_mode, val);
99 }
100 
l3_set_gpio_ops(struct device * dev,struct l3_pins * adap)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");
133