2019-05-30 02:57:50 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-12-10 17:41:33 +03:00
/*
* MFD driver for wl1273 FM radio and audio codec submodules .
*
2011-03-01 16:10:35 +03:00
* Copyright ( C ) 2011 Nokia Corporation
2010-12-10 17:41:33 +03:00
* Author : Matti Aaltonen < matti . j . aaltonen @ nokia . com >
*/
# include <linux/mfd/wl1273-core.h>
# include <linux/slab.h>
2011-07-03 23:13:27 +04:00
# include <linux/module.h>
2010-12-10 17:41:33 +03:00
# define DRIVER_DESC "WL1273 FM Radio Core"
2011-03-23 15:54:17 +03:00
static const struct i2c_device_id wl1273_driver_id_table [ ] = {
2010-12-10 17:41:33 +03:00
{ WL1273_FM_DRIVER_NAME , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , wl1273_driver_id_table ) ;
2011-03-01 16:10:35 +03:00
static int wl1273_fm_read_reg ( struct wl1273_core * core , u8 reg , u16 * value )
{
struct i2c_client * client = core - > client ;
u8 b [ 2 ] ;
int r ;
r = i2c_smbus_read_i2c_block_data ( client , reg , sizeof ( b ) , b ) ;
if ( r ! = 2 ) {
dev_err ( & client - > dev , " %s: Read: %d fails. \n " , __func__ , reg ) ;
return - EREMOTEIO ;
}
* value = ( u16 ) b [ 0 ] < < 8 | b [ 1 ] ;
return 0 ;
}
static int wl1273_fm_write_cmd ( struct wl1273_core * core , u8 cmd , u16 param )
{
struct i2c_client * client = core - > client ;
u8 buf [ ] = { ( param > > 8 ) & 0xff , param & 0xff } ;
int r ;
r = i2c_smbus_write_i2c_block_data ( client , cmd , sizeof ( buf ) , buf ) ;
if ( r ) {
dev_err ( & client - > dev , " %s: Cmd: %d fails. \n " , __func__ , cmd ) ;
return r ;
}
return 0 ;
}
static int wl1273_fm_write_data ( struct wl1273_core * core , u8 * data , u16 len )
{
struct i2c_client * client = core - > client ;
struct i2c_msg msg ;
int r ;
msg . addr = client - > addr ;
msg . flags = 0 ;
msg . buf = data ;
msg . len = len ;
r = i2c_transfer ( client - > adapter , & msg , 1 ) ;
if ( r ! = 1 ) {
dev_err ( & client - > dev , " %s: write error. \n " , __func__ ) ;
return - EREMOTEIO ;
}
return 0 ;
}
/**
* wl1273_fm_set_audio ( ) - Set audio mode .
* @ core : A pointer to the device struct .
* @ new_mode : The new audio mode .
*
* Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG .
*/
static int wl1273_fm_set_audio ( struct wl1273_core * core , unsigned int new_mode )
{
int r = 0 ;
if ( core - > mode = = WL1273_MODE_OFF | |
core - > mode = = WL1273_MODE_SUSPENDED )
return - EPERM ;
if ( core - > mode = = WL1273_MODE_RX & & new_mode = = WL1273_AUDIO_DIGITAL ) {
r = wl1273_fm_write_cmd ( core , WL1273_PCM_MODE_SET ,
WL1273_PCM_DEF_MODE ) ;
if ( r )
goto out ;
r = wl1273_fm_write_cmd ( core , WL1273_I2S_MODE_CONFIG_SET ,
core - > i2s_mode ) ;
if ( r )
goto out ;
r = wl1273_fm_write_cmd ( core , WL1273_AUDIO_ENABLE ,
WL1273_AUDIO_ENABLE_I2S ) ;
if ( r )
goto out ;
} else if ( core - > mode = = WL1273_MODE_RX & &
new_mode = = WL1273_AUDIO_ANALOG ) {
r = wl1273_fm_write_cmd ( core , WL1273_AUDIO_ENABLE ,
WL1273_AUDIO_ENABLE_ANALOG ) ;
if ( r )
goto out ;
} else if ( core - > mode = = WL1273_MODE_TX & &
new_mode = = WL1273_AUDIO_DIGITAL ) {
r = wl1273_fm_write_cmd ( core , WL1273_I2S_MODE_CONFIG_SET ,
core - > i2s_mode ) ;
if ( r )
goto out ;
r = wl1273_fm_write_cmd ( core , WL1273_AUDIO_IO_SET ,
WL1273_AUDIO_IO_SET_I2S ) ;
if ( r )
goto out ;
} else if ( core - > mode = = WL1273_MODE_TX & &
new_mode = = WL1273_AUDIO_ANALOG ) {
r = wl1273_fm_write_cmd ( core , WL1273_AUDIO_IO_SET ,
WL1273_AUDIO_IO_SET_ANALOG ) ;
if ( r )
goto out ;
}
core - > audio_mode = new_mode ;
out :
return r ;
}
/**
* wl1273_fm_set_volume ( ) - Set volume .
* @ core : A pointer to the device struct .
* @ volume : The new volume value .
*/
static int wl1273_fm_set_volume ( struct wl1273_core * core , unsigned int volume )
{
int r ;
if ( volume > WL1273_MAX_VOLUME )
return - EINVAL ;
if ( core - > volume = = volume )
return 0 ;
r = wl1273_fm_write_cmd ( core , WL1273_VOLUME_SET , volume ) ;
if ( r )
return r ;
core - > volume = volume ;
return 0 ;
}
2012-11-19 22:23:04 +04:00
static int wl1273_core_probe ( struct i2c_client * client ,
2010-12-10 17:41:33 +03:00
const struct i2c_device_id * id )
{
2013-07-30 12:10:05 +04:00
struct wl1273_fm_platform_data * pdata = dev_get_platdata ( & client - > dev ) ;
2010-12-10 17:41:33 +03:00
struct wl1273_core * core ;
struct mfd_cell * cell ;
int children = 0 ;
int r = 0 ;
dev_dbg ( & client - > dev , " %s \n " , __func__ ) ;
if ( ! pdata ) {
dev_err ( & client - > dev , " No platform data. \n " ) ;
return - EINVAL ;
}
if ( ! ( pdata - > children & WL1273_RADIO_CHILD ) ) {
dev_err ( & client - > dev , " Cannot function without radio child. \n " ) ;
return - EINVAL ;
}
2013-08-20 11:06:17 +04:00
core = devm_kzalloc ( & client - > dev , sizeof ( * core ) , GFP_KERNEL ) ;
2010-12-10 17:41:33 +03:00
if ( ! core )
return - ENOMEM ;
core - > pdata = pdata ;
core - > client = client ;
mutex_init ( & core - > lock ) ;
i2c_set_clientdata ( client , core ) ;
dev_dbg ( & client - > dev , " %s: Have V4L2. \n " , __func__ ) ;
cell = & core - > cells [ children ] ;
cell - > name = " wl1273_fm_radio " ;
2011-04-06 13:56:04 +04:00
cell - > platform_data = & core ;
cell - > pdata_size = sizeof ( core ) ;
2010-12-10 17:41:33 +03:00
children + + ;
2011-03-01 16:10:35 +03:00
core - > read = wl1273_fm_read_reg ;
core - > write = wl1273_fm_write_cmd ;
core - > write_data = wl1273_fm_write_data ;
core - > set_audio = wl1273_fm_set_audio ;
core - > set_volume = wl1273_fm_set_volume ;
2010-12-10 17:41:33 +03:00
if ( pdata - > children & WL1273_CODEC_CHILD ) {
cell = & core - > cells [ children ] ;
dev_dbg ( & client - > dev , " %s: Have codec. \n " , __func__ ) ;
cell - > name = " wl1273-codec " ;
2011-04-06 13:56:04 +04:00
cell - > platform_data = & core ;
cell - > pdata_size = sizeof ( core ) ;
2010-12-10 17:41:33 +03:00
children + + ;
}
dev_dbg ( & client - > dev , " %s: number of children: %d. \n " ,
__func__ , children ) ;
2016-04-21 15:25:58 +03:00
r = devm_mfd_add_devices ( & client - > dev , - 1 , core - > cells ,
children , NULL , 0 , NULL ) ;
2010-12-10 17:41:33 +03:00
if ( r )
goto err ;
return 0 ;
err :
pdata - > free_resources ( ) ;
dev_dbg ( & client - > dev , " %s \n " , __func__ ) ;
return r ;
}
static struct i2c_driver wl1273_core_driver = {
. driver = {
. name = WL1273_FM_DRIVER_NAME ,
} ,
. probe = wl1273_core_probe ,
. id_table = wl1273_driver_id_table ,
} ;
static int __init wl1273_core_init ( void )
{
int r ;
r = i2c_add_driver ( & wl1273_core_driver ) ;
if ( r ) {
pr_err ( WL1273_FM_DRIVER_NAME
" : driver registration failed \n " ) ;
return r ;
}
return r ;
}
static void __exit wl1273_core_exit ( void )
{
i2c_del_driver ( & wl1273_core_driver ) ;
}
late_initcall ( wl1273_core_init ) ;
module_exit ( wl1273_core_exit ) ;
MODULE_AUTHOR ( " Matti Aaltonen <matti.j.aaltonen@nokia.com> " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;