2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-11-15 10:58:16 +03:00
/*
* L3 code
*
* Copyright ( C ) 2008 , Christian Pellegrin < chripell @ evolware . org >
*
* based on :
*
* L3 bus algorithm module .
*
* Copyright ( C ) 2001 Russell King , All Rights Reserved .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/delay.h>
2016-08-04 16:38:41 +03:00
# include <linux/device.h>
# include <linux/gpio.h>
2008-11-15 10:58:16 +03:00
# include <sound/l3.h>
/*
* Send one byte of data to the chip . Data is latched into the chip on
* the rising edge of the clock .
*/
static void sendbyte ( struct l3_pins * adap , unsigned int byte )
{
int i ;
for ( i = 0 ; i < 8 ; i + + ) {
2016-08-04 16:38:41 +03:00
adap - > setclk ( adap , 0 ) ;
2008-11-15 10:58:16 +03:00
udelay ( adap - > data_hold ) ;
2016-08-04 16:38:41 +03:00
adap - > setdat ( adap , byte & 1 ) ;
2008-11-15 10:58:16 +03:00
udelay ( adap - > data_setup ) ;
2016-08-04 16:38:41 +03:00
adap - > setclk ( adap , 1 ) ;
2008-11-15 10:58:16 +03:00
udelay ( adap - > clock_high ) ;
byte > > = 1 ;
}
}
/*
* Send a set of bytes to the chip . We need to pulse the MODE line
* between each byte , but never at the start nor at the end of the
* transfer .
*/
static void sendbytes ( struct l3_pins * adap , const u8 * buf ,
int len )
{
int i ;
for ( i = 0 ; i < len ; i + + ) {
if ( i ) {
udelay ( adap - > mode_hold ) ;
2016-08-04 16:38:41 +03:00
adap - > setmode ( adap , 0 ) ;
2008-11-15 10:58:16 +03:00
udelay ( adap - > mode ) ;
}
2016-08-04 16:38:41 +03:00
adap - > setmode ( adap , 1 ) ;
2008-11-15 10:58:16 +03:00
udelay ( adap - > mode_setup ) ;
sendbyte ( adap , buf [ i ] ) ;
}
}
int l3_write ( struct l3_pins * adap , u8 addr , u8 * data , int len )
{
2016-08-04 16:38:41 +03:00
adap - > setclk ( adap , 1 ) ;
adap - > setdat ( adap , 1 ) ;
adap - > setmode ( adap , 1 ) ;
2008-11-15 10:58:16 +03:00
udelay ( adap - > mode ) ;
2016-08-04 16:38:41 +03:00
adap - > setmode ( adap , 0 ) ;
2008-11-15 10:58:16 +03:00
udelay ( adap - > mode_setup ) ;
sendbyte ( adap , addr ) ;
udelay ( adap - > mode_hold ) ;
sendbytes ( adap , data , len ) ;
2016-08-04 16:38:41 +03:00
adap - > setclk ( adap , 1 ) ;
adap - > setdat ( adap , 1 ) ;
adap - > setmode ( adap , 0 ) ;
2008-11-15 10:58:16 +03:00
return len ;
}
EXPORT_SYMBOL_GPL ( l3_write ) ;
2016-08-04 16:38:41 +03:00
static void l3_set_clk ( struct l3_pins * adap , int val )
{
gpio_set_value ( adap - > gpio_clk , val ) ;
}
static void l3_set_data ( struct l3_pins * adap , int val )
{
gpio_set_value ( adap - > gpio_data , val ) ;
}
static void l3_set_mode ( struct l3_pins * adap , int val )
{
gpio_set_value ( adap - > gpio_mode , val ) ;
}
int l3_set_gpio_ops ( struct device * dev , struct l3_pins * adap )
{
int ret ;
if ( ! adap - > use_gpios )
return - EINVAL ;
ret = devm_gpio_request_one ( dev , adap - > gpio_data ,
GPIOF_OUT_INIT_LOW , " l3_data " ) ;
if ( ret < 0 )
return ret ;
adap - > setdat = l3_set_data ;
ret = devm_gpio_request_one ( dev , adap - > gpio_clk ,
GPIOF_OUT_INIT_LOW , " l3_clk " ) ;
if ( ret < 0 )
return ret ;
adap - > setclk = l3_set_clk ;
ret = devm_gpio_request_one ( dev , adap - > gpio_mode ,
GPIOF_OUT_INIT_LOW , " l3_mode " ) ;
if ( ret < 0 )
return ret ;
adap - > setmode = l3_set_mode ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( l3_set_gpio_ops ) ;
2008-11-15 10:58:16 +03:00
MODULE_DESCRIPTION ( " L3 bit-banging driver " ) ;
MODULE_AUTHOR ( " Christian Pellegrin <chripell@evolware.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;