l3.c (2674B)
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 */ 26static 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 */ 46static 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 63int 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} 83EXPORT_SYMBOL_GPL(l3_write); 84 85 86static void l3_set_clk(struct l3_pins *adap, int val) 87{ 88 gpio_set_value(adap->gpio_clk, val); 89} 90 91static void l3_set_data(struct l3_pins *adap, int val) 92{ 93 gpio_set_value(adap->gpio_data, val); 94} 95 96static void l3_set_mode(struct l3_pins *adap, int val) 97{ 98 gpio_set_value(adap->gpio_mode, val); 99} 100 101int 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} 128EXPORT_SYMBOL_GPL(l3_set_gpio_ops); 129 130MODULE_DESCRIPTION("L3 bit-banging driver"); 131MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); 132MODULE_LICENSE("GPL");