asoc tlv320aic3x: add GPIO support
Subsystems (3)
PATCH 2/3 asoc tlv320aic3x: add GPIO support
This patch adds support for AIC3x GPIO lines. They can be configured for many possible functions as well as be driven manually. I also introduced i2c read functionality since the GPIO state register has to be read from hardware every time and can not be served from cache.
sound/soc/codecs/tlv320aic3x.c +53 -0
@@ -140,6 +140,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,return -EIO ; } +/* +* read from the aic3x register space +*/ +static int aic3x_read (struct snd_soc_codec *codec,unsigned int reg, +u8 *value) +{ + *value = reg &0xff ; +if (codec->hw_read (codec->control_data, value,1 ) !=1 ) +return -EIO ; + +aic3x_write_reg_cache (codec, reg, *value); +return 0 ; +} +#define SOC_DAPM_SINGLE_AIC3X (xname, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \
@@ -913,6 +927,33 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)return 0 ; } +void aic3x_set_gpio (struct snd_soc_codec *codec,int gpio,int state) +{ +u8 reg = gpio ?AIC3X_GPIO2_REG :AIC3X_GPIO1_REG ; +u8 bit = gpio ?3 :0 ; +u8 val =aic3x_read_reg_cache (codec, reg) & ~(1 << bit); +aic3x_write (codec, reg, val | (!!state << bit)); +} +EXPORT_SYMBOL_GPL (aic3x_set_gpio); + +int aic3x_get_gpio (struct snd_soc_codec *codec,int gpio) +{ +u8 reg = gpio ?AIC3X_GPIO2_REG :AIC3X_GPIO1_REG ; +u8 val, bit = gpio ?2 :1 ; + +aic3x_read (codec, reg, &val); +return !!(val & (1 << bit)); +} +EXPORT_SYMBOL_GPL (aic3x_get_gpio); + +int aic3x_headset_detected (struct snd_soc_codec *codec) +{ +u8 val; +aic3x_read (codec,AIC3X_RT_IRQ_FLAGS_REG , &val); +return !!(val & (1 <<2 )); +} +EXPORT_SYMBOL_GPL (aic3x_headset_detected); +#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -979,6 +1020,7 @@ static int aic3x_resume(struct platform_device *pdev)static int aic3x_init (struct snd_soc_device *socdev) {struct snd_soc_codec *codec = socdev->codec; +struct aic3x_setup_data *setup = socdev->codec_data;int reg, ret =0 ; codec->name ="aic3x" ;
@@ -1069,6 +1111,10 @@ static int aic3x_init(struct snd_soc_device *socdev)/* off, with power on */ aic3x_dapm_event (codec, SNDRV_CTL_POWER_D3hot); +/* setup GPIO functions */ +aic3x_write (codec,AIC3X_GPIO1_REG , (setup->gpio_func[0 ] &0xf ) <<4 ); +aic3x_write (codec,AIC3X_GPIO2_REG , (setup->gpio_func[1 ] &0xf ) <<4 ); +aic3x_add_controls (codec);aic3x_add_widgets (codec); ret =snd_soc_register_card (socdev);
@@ -1176,6 +1222,12 @@ static struct i2c_client client_template = { .name = "AIC3X", .driver = &aic3x_i2c_driver, }; + +static int aic3x_i2c_read (struct i2c_client *client,u8 *value,int len) +{ + value[0 ] =i2c_smbus_read_byte_data (client, value[0 ]); +return (len ==1 ); +}#endif static int aic3x_probe (struct platform_device *pdev)
@@ -1210,6 +1262,7 @@ static int aic3x_probe(struct platform_device *pdev)if (setup->i2c_address) { normal_i2c[0 ] = setup->i2c_address; codec->hw_write = (hw_write_t ) i2c_master_send; + codec->hw_read = (hw_read_t ) aic3x_i2c_read; ret =i2c_add_driver (&aic3x_i2c_driver);if (ret !=0 )printk (KERN_ERR "can't add i2c driver" );
sound/soc/codecs/tlv320aic3x.h +48 -1
64 lines not on this page · raw message
_______________________________________________
Alsa-devel mailing list
[email protected]
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
At Fri, 25 Apr 2008 11:17:52 +0200,
sound/soc/codecs/tlv320aic3x.c static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) · line 945
Quoted 8 lines · Daniel Mack
sound/soc/codecs/tlv320aic3x.c +7
-0+int aic3x_get_gpio (struct snd_soc_codec *codec,int gpio) +{ +u8 reg = gpio ?AIC3X_GPIO2_REG :AIC3X_GPIO1_REG ; +u8 val, bit = gpio ?2 :1 ; + +aic3x_read (codec, reg, &val); +return !!(val & (1 << bit));
I prefer a form like
return (val >> bit) & 1;
"!!" often makes hard to read.
Takashi
Quoted 9 lines · Takashi Iwai
Review
Quoted 7 lines
(quoted diff) +7
-0+int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) +{ + u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; + u8 val, bit = gpio ? 2: 1; + + aic3x_read(codec, reg, &val); + return !!(val & (1 << bit));I prefer a form like
Quoted 3 lines
return (val >> bit) & 1;"!!" often makes hard to read.
Ok, agreed. New patch below.
Best regards,
Daniel
sound/soc/codecs/tlv320aic3x.c +53 -0
@@ -139,6 +139,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,return -EIO ; } +/* +* read from the aic3x register space +*/ +static int aic3x_read (struct snd_soc_codec *codec,unsigned int reg, +u8 *value) +{ + *value = reg &0xff ; +if (codec->hw_read (codec->control_data, value,1 ) !=1 ) +return -EIO ; + +aic3x_write_reg_cache (codec, reg, *value); +return 0 ; +} +#define SOC_DAPM_SINGLE_AIC3X (xname, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \
@@ -912,6 +926,33 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)return 0 ; } +void aic3x_set_gpio (struct snd_soc_codec *codec,int gpio,int state) +{ +u8 reg = gpio ?AIC3X_GPIO2_REG :AIC3X_GPIO1_REG ; +u8 bit = gpio ?3 :0 ; +u8 val =aic3x_read_reg_cache (codec, reg) & ~(1 << bit); +aic3x_write (codec, reg, val | (!!state << bit)); +} +EXPORT_SYMBOL_GPL (aic3x_set_gpio); + +int aic3x_get_gpio (struct snd_soc_codec *codec,int gpio) +{ +u8 reg = gpio ?AIC3X_GPIO2_REG :AIC3X_GPIO1_REG ; +u8 val, bit = gpio ?2 :1 ; + +aic3x_read (codec, reg, &val); +return (val >> bit) &1 ; +} +EXPORT_SYMBOL_GPL (aic3x_get_gpio); + +int aic3x_headset_detected (struct snd_soc_codec *codec) +{ +u8 val; +aic3x_read (codec,AIC3X_RT_IRQ_FLAGS_REG , &val); +return (val >>2 ) &1 ; +} +EXPORT_SYMBOL_GPL (aic3x_headset_detected); +#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -978,6 +1019,7 @@ static int aic3x_resume(struct platform_device *pdev)static int aic3x_init (struct snd_soc_device *socdev) {struct snd_soc_codec *codec = socdev->codec; +struct aic3x_setup_data *setup = socdev->codec_data;int reg, ret =0 ; codec->name ="aic3x" ;
@@ -1068,6 +1110,10 @@ static int aic3x_init(struct snd_soc_device *socdev)/* off, with power on */ aic3x_dapm_event (codec, SNDRV_CTL_POWER_D3hot); +/* setup GPIO functions */ +aic3x_write (codec,AIC3X_GPIO1_REG , (setup->gpio_func[0 ] &0xf ) <<4 ); +aic3x_write (codec,AIC3X_GPIO2_REG , (setup->gpio_func[1 ] &0xf ) <<4 ); +aic3x_add_controls (codec);aic3x_add_widgets (codec); ret =snd_soc_register_card (socdev);
@@ -1175,6 +1221,12 @@ static struct i2c_client client_template = { .name = "AIC3X", .driver = &aic3x_i2c_driver, }; + +static int aic3x_i2c_read (struct i2c_client *client,u8 *value,int len) +{ + value[0 ] =i2c_smbus_read_byte_data (client, value[0 ]); +return (len ==1 ); +}#endif static int aic3x_probe (struct platform_device *pdev)
@@ -1209,6 +1261,7 @@ static int aic3x_probe(struct platform_device *pdev)if (setup->i2c_address) { normal_i2c[0 ] = setup->i2c_address; codec->hw_write = (hw_write_t ) i2c_master_send; + codec->hw_read = (hw_read_t ) aic3x_i2c_read; ret =i2c_add_driver (&aic3x_i2c_driver);if (ret !=0 )printk (KERN_ERR "can't add i2c driver" );
sound/soc/codecs/tlv320aic3x.h +48 -1
64 lines not on this page · raw message
_______________________________________________
Alsa-devel mailing list
[email protected]
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Quoted 9 lines · Takashi Iwai
Review
Quoted 7 lines
(quoted diff) +7
-0+int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) +{ + u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; + u8 val, bit = gpio ? 2: 1; + + aic3x_read(codec, reg, &val); + return !!(val & (1 << bit));I prefer a form like
Quoted 3 lines
return (val >> bit) & 1;"!!" often makes hard to read.
Patch rebased to match with other changes introduced by the clocking patch.
Daniel
sound/soc/codecs/tlv320aic3x.c +53 -0
@@ -138,6 +138,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,return -EIO ; } +/* +* read from the aic3x register space +*/ +static int aic3x_read (struct snd_soc_codec *codec,unsigned int reg, +u8 *value) +{ + *value = reg &0xff ; +if (codec->hw_read (codec->control_data, value,1 ) !=1 ) +return -EIO ; + +aic3x_write_reg_cache (codec, reg, *value); +return 0 ; +} +#define SOC_DAPM_SINGLE_AIC3X (xname, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \
@@ -911,6 +925,33 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)return 0 ; } +void aic3x_set_gpio (struct snd_soc_codec *codec,int gpio,int state) +{ +u8 reg = gpio ?AIC3X_GPIO2_REG :AIC3X_GPIO1_REG ; +u8 bit = gpio ?3 :0 ; +u8 val =aic3x_read_reg_cache (codec, reg) & ~(1 << bit); +aic3x_write (codec, reg, val | (!!state << bit)); +} +EXPORT_SYMBOL_GPL (aic3x_set_gpio); + +int aic3x_get_gpio (struct snd_soc_codec *codec,int gpio) +{ +u8 reg = gpio ?AIC3X_GPIO2_REG :AIC3X_GPIO1_REG ; +u8 val, bit = gpio ?2 :1 ; + +aic3x_read (codec, reg, &val); +return (val >> bit) &1 ; +} +EXPORT_SYMBOL_GPL (aic3x_get_gpio); + +int aic3x_headset_detected (struct snd_soc_codec *codec) +{ +u8 val; +aic3x_read (codec,AIC3X_RT_IRQ_FLAGS_REG , &val); +return (val >>2 ) &1 ; +} +EXPORT_SYMBOL_GPL (aic3x_headset_detected); +#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -977,6 +1018,7 @@ static int aic3x_resume(struct platform_device *pdev)static int aic3x_init (struct snd_soc_device *socdev) {struct snd_soc_codec *codec = socdev->codec; +struct aic3x_setup_data *setup = socdev->codec_data;int reg, ret =0 ; codec->name ="aic3x" ;
@@ -1067,6 +1109,10 @@ static int aic3x_init(struct snd_soc_device *socdev)/* off, with power on */ aic3x_dapm_event (codec, SNDRV_CTL_POWER_D3hot); +/* setup GPIO functions */ +aic3x_write (codec,AIC3X_GPIO1_REG , (setup->gpio_func[0 ] &0xf ) <<4 ); +aic3x_write (codec,AIC3X_GPIO2_REG , (setup->gpio_func[1 ] &0xf ) <<4 ); +aic3x_add_controls (codec);aic3x_add_widgets (codec); ret =snd_soc_register_card (socdev);
@@ -1174,6 +1220,12 @@ static struct i2c_client client_template = { .name = "AIC3X", .driver = &aic3x_i2c_driver, }; + +static int aic3x_i2c_read (struct i2c_client *client,u8 *value,int len) +{ + value[0 ] =i2c_smbus_read_byte_data (client, value[0 ]); +return (len ==1 ); +}#endif static int aic3x_probe (struct platform_device *pdev)
@@ -1208,6 +1260,7 @@ static int aic3x_probe(struct platform_device *pdev)if (setup->i2c_address) { normal_i2c[0 ] = setup->i2c_address; codec->hw_write = (hw_write_t ) i2c_master_send; + codec->hw_read = (hw_read_t ) aic3x_i2c_read; ret =i2c_add_driver (&aic3x_i2c_driver);if (ret !=0 )printk (KERN_ERR "can't add i2c driver" );
sound/soc/codecs/tlv320aic3x.h +48 -1
64 lines not on this page · raw message
_______________________________________________
Alsa-devel mailing list
[email protected]
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel