Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
09fd19da
Commit
09fd19da
authored
Jan 21, 2014
by
Lee Jones
Browse files
Options
Browse Files
Download
Plain Diff
Merge tag 'ib-asoc-3.14.2' into for-mfd-next
Immutable branch between MFD and ASoC due for the v3.14 merge window
parents
6eb37eb2
91460700
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
255 additions
and
30 deletions
+255
-30
drivers/mfd/twl-core.c
drivers/mfd/twl-core.c
+163
-27
drivers/mfd/twl6040.c
drivers/mfd/twl6040.c
+89
-3
include/linux/i2c/twl.h
include/linux/i2c/twl.h
+3
-0
No files found.
drivers/mfd/twl-core.c
View file @
09fd19da
...
...
@@ -47,6 +47,9 @@
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
/* Register descriptions for audio */
#include <linux/mfd/twl4030-audio.h>
#include "twl-core.h"
/*
...
...
@@ -200,6 +203,105 @@ static struct twl_mapping twl4030_map[] = {
{
2
,
TWL5031_BASEADD_INTERRUPTS
},
};
static
struct
reg_default
twl4030_49_defaults
[]
=
{
/* Audio Registers */
{
0x01
,
0x00
},
/* CODEC_MODE */
{
0x02
,
0x00
},
/* OPTION */
/* 0x03 Unused */
{
0x04
,
0x00
},
/* MICBIAS_CTL */
{
0x05
,
0x00
},
/* ANAMICL */
{
0x06
,
0x00
},
/* ANAMICR */
{
0x07
,
0x00
},
/* AVADC_CTL */
{
0x08
,
0x00
},
/* ADCMICSEL */
{
0x09
,
0x00
},
/* DIGMIXING */
{
0x0a
,
0x0f
},
/* ATXL1PGA */
{
0x0b
,
0x0f
},
/* ATXR1PGA */
{
0x0c
,
0x0f
},
/* AVTXL2PGA */
{
0x0d
,
0x0f
},
/* AVTXR2PGA */
{
0x0e
,
0x00
},
/* AUDIO_IF */
{
0x0f
,
0x00
},
/* VOICE_IF */
{
0x10
,
0x3f
},
/* ARXR1PGA */
{
0x11
,
0x3f
},
/* ARXL1PGA */
{
0x12
,
0x3f
},
/* ARXR2PGA */
{
0x13
,
0x3f
},
/* ARXL2PGA */
{
0x14
,
0x25
},
/* VRXPGA */
{
0x15
,
0x00
},
/* VSTPGA */
{
0x16
,
0x00
},
/* VRX2ARXPGA */
{
0x17
,
0x00
},
/* AVDAC_CTL */
{
0x18
,
0x00
},
/* ARX2VTXPGA */
{
0x19
,
0x32
},
/* ARXL1_APGA_CTL*/
{
0x1a
,
0x32
},
/* ARXR1_APGA_CTL*/
{
0x1b
,
0x32
},
/* ARXL2_APGA_CTL*/
{
0x1c
,
0x32
},
/* ARXR2_APGA_CTL*/
{
0x1d
,
0x00
},
/* ATX2ARXPGA */
{
0x1e
,
0x00
},
/* BT_IF */
{
0x1f
,
0x55
},
/* BTPGA */
{
0x20
,
0x00
},
/* BTSTPGA */
{
0x21
,
0x00
},
/* EAR_CTL */
{
0x22
,
0x00
},
/* HS_SEL */
{
0x23
,
0x00
},
/* HS_GAIN_SET */
{
0x24
,
0x00
},
/* HS_POPN_SET */
{
0x25
,
0x00
},
/* PREDL_CTL */
{
0x26
,
0x00
},
/* PREDR_CTL */
{
0x27
,
0x00
},
/* PRECKL_CTL */
{
0x28
,
0x00
},
/* PRECKR_CTL */
{
0x29
,
0x00
},
/* HFL_CTL */
{
0x2a
,
0x00
},
/* HFR_CTL */
{
0x2b
,
0x05
},
/* ALC_CTL */
{
0x2c
,
0x00
},
/* ALC_SET1 */
{
0x2d
,
0x00
},
/* ALC_SET2 */
{
0x2e
,
0x00
},
/* BOOST_CTL */
{
0x2f
,
0x00
},
/* SOFTVOL_CTL */
{
0x30
,
0x13
},
/* DTMF_FREQSEL */
{
0x31
,
0x00
},
/* DTMF_TONEXT1H */
{
0x32
,
0x00
},
/* DTMF_TONEXT1L */
{
0x33
,
0x00
},
/* DTMF_TONEXT2H */
{
0x34
,
0x00
},
/* DTMF_TONEXT2L */
{
0x35
,
0x79
},
/* DTMF_TONOFF */
{
0x36
,
0x11
},
/* DTMF_WANONOFF */
{
0x37
,
0x00
},
/* I2S_RX_SCRAMBLE_H */
{
0x38
,
0x00
},
/* I2S_RX_SCRAMBLE_M */
{
0x39
,
0x00
},
/* I2S_RX_SCRAMBLE_L */
{
0x3a
,
0x06
},
/* APLL_CTL */
{
0x3b
,
0x00
},
/* DTMF_CTL */
{
0x3c
,
0x44
},
/* DTMF_PGA_CTL2 (0x3C) */
{
0x3d
,
0x69
},
/* DTMF_PGA_CTL1 (0x3D) */
{
0x3e
,
0x00
},
/* MISC_SET_1 */
{
0x3f
,
0x00
},
/* PCMBTMUX */
/* 0x40 - 0x42 Unused */
{
0x43
,
0x00
},
/* RX_PATH_SEL */
{
0x44
,
0x32
},
/* VDL_APGA_CTL */
{
0x45
,
0x00
},
/* VIBRA_CTL */
{
0x46
,
0x00
},
/* VIBRA_SET */
{
0x47
,
0x00
},
/* VIBRA_PWM_SET */
{
0x48
,
0x00
},
/* ANAMIC_GAIN */
{
0x49
,
0x00
},
/* MISC_SET_2 */
/* End of Audio Registers */
};
static
bool
twl4030_49_nop_reg
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
0
:
case
3
:
case
40
:
case
41
:
case
42
:
return
false
;
default:
return
true
;
}
}
static
const
struct
regmap_range
twl4030_49_volatile_ranges
[]
=
{
regmap_reg_range
(
TWL4030_BASEADD_TEST
,
0xff
),
};
static
const
struct
regmap_access_table
twl4030_49_volatile_table
=
{
.
yes_ranges
=
twl4030_49_volatile_ranges
,
.
n_yes_ranges
=
ARRAY_SIZE
(
twl4030_49_volatile_ranges
),
};
static
struct
regmap_config
twl4030_regmap_config
[
4
]
=
{
{
/* Address 0x48 */
...
...
@@ -212,6 +314,15 @@ static struct regmap_config twl4030_regmap_config[4] = {
.
reg_bits
=
8
,
.
val_bits
=
8
,
.
max_register
=
0xff
,
.
readable_reg
=
twl4030_49_nop_reg
,
.
writeable_reg
=
twl4030_49_nop_reg
,
.
volatile_table
=
&
twl4030_49_volatile_table
,
.
reg_defaults
=
twl4030_49_defaults
,
.
num_reg_defaults
=
ARRAY_SIZE
(
twl4030_49_defaults
),
.
cache_type
=
REGCACHE_RBTREE
,
},
{
/* Address 0x4a */
...
...
@@ -302,35 +413,50 @@ unsigned int twl_rev(void)
EXPORT_SYMBOL
(
twl_rev
);
/**
* twl_
i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
* twl_
get_regmap - Get the regmap associated with the given module
* @mod_no: module number
* @value: an array of num_bytes+1 containing data to write
* @reg: register address (just offset will do)
* @num_bytes: number of bytes to transfer
*
* Returns the re
sult of operation - 0 is success
* Returns the re
gmap pointer or NULL in case of failure.
*/
int
twl_i2c_write
(
u8
mod_no
,
u8
*
value
,
u8
reg
,
unsigned
num_bytes
)
static
struct
regmap
*
twl_get_regmap
(
u8
mod_no
)
{
int
ret
;
int
sid
;
struct
twl_client
*
twl
;
if
(
unlikely
(
!
twl_priv
||
!
twl_priv
->
ready
))
{
pr_err
(
"%s: not initialized
\n
"
,
DRIVER_NAME
);
return
-
EPERM
;
return
NULL
;
}
if
(
unlikely
(
mod_no
>=
twl_get_last_module
()))
{
pr_err
(
"%s: invalid module number %d
\n
"
,
DRIVER_NAME
,
mod_no
);
return
-
EPERM
;
return
NULL
;
}
sid
=
twl_priv
->
twl_map
[
mod_no
].
sid
;
twl
=
&
twl_priv
->
twl_modules
[
sid
];
ret
=
regmap_bulk_write
(
twl
->
regmap
,
twl_priv
->
twl_map
[
mod_no
].
base
+
reg
,
value
,
num_bytes
);
return
twl
->
regmap
;
}
/**
* twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
* @mod_no: module number
* @value: an array of num_bytes+1 containing data to write
* @reg: register address (just offset will do)
* @num_bytes: number of bytes to transfer
*
* Returns the result of operation - 0 is success
*/
int
twl_i2c_write
(
u8
mod_no
,
u8
*
value
,
u8
reg
,
unsigned
num_bytes
)
{
struct
regmap
*
regmap
=
twl_get_regmap
(
mod_no
);
int
ret
;
if
(
!
regmap
)
return
-
EPERM
;
ret
=
regmap_bulk_write
(
regmap
,
twl_priv
->
twl_map
[
mod_no
].
base
+
reg
,
value
,
num_bytes
);
if
(
ret
)
pr_err
(
"%s: Write failed (mod %d, reg 0x%02x count %d)
\n
"
,
...
...
@@ -351,25 +477,14 @@ EXPORT_SYMBOL(twl_i2c_write);
*/
int
twl_i2c_read
(
u8
mod_no
,
u8
*
value
,
u8
reg
,
unsigned
num_bytes
)
{
struct
regmap
*
regmap
=
twl_get_regmap
(
mod_no
);
int
ret
;
int
sid
;
struct
twl_client
*
twl
;
if
(
unlikely
(
!
twl_priv
||
!
twl_priv
->
ready
))
{
pr_err
(
"%s: not initialized
\n
"
,
DRIVER_NAME
);
return
-
EPERM
;
}
if
(
unlikely
(
mod_no
>=
twl_get_last_module
()))
{
pr_err
(
"%s: invalid module number %d
\n
"
,
DRIVER_NAME
,
mod_no
);
if
(
!
regmap
)
return
-
EPERM
;
}
sid
=
twl_priv
->
twl_map
[
mod_no
].
sid
;
twl
=
&
twl_priv
->
twl_modules
[
sid
];
ret
=
regmap_bulk_read
(
twl
->
regmap
,
twl_priv
->
twl_map
[
mod_no
].
base
+
reg
,
value
,
num_bytes
);
ret
=
regmap_bulk_read
(
regmap
,
twl_priv
->
twl_map
[
mod_no
].
base
+
reg
,
value
,
num_bytes
);
if
(
ret
)
pr_err
(
"%s: Read failed (mod %d, reg 0x%02x count %d)
\n
"
,
...
...
@@ -379,6 +494,27 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
}
EXPORT_SYMBOL
(
twl_i2c_read
);
/**
* twl_regcache_bypass - Configure the regcache bypass for the regmap associated
* with the module
* @mod_no: module number
* @enable: Regcache bypass state
*
* Returns 0 else failure.
*/
int
twl_set_regcache_bypass
(
u8
mod_no
,
bool
enable
)
{
struct
regmap
*
regmap
=
twl_get_regmap
(
mod_no
);
if
(
!
regmap
)
return
-
EPERM
;
regcache_cache_bypass
(
regmap
,
enable
);
return
0
;
}
EXPORT_SYMBOL
(
twl_set_regcache_bypass
);
/*----------------------------------------------------------------------*/
/**
...
...
drivers/mfd/twl6040.c
View file @
09fd19da
...
...
@@ -44,6 +44,54 @@
#define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1)
#define TWL6040_NUM_SUPPLIES (2)
static
struct
reg_default
twl6040_defaults
[]
=
{
{
0x01
,
0x4B
},
/* REG_ASICID (ro) */
{
0x02
,
0x00
},
/* REG_ASICREV (ro) */
{
0x03
,
0x00
},
/* REG_INTID */
{
0x04
,
0x00
},
/* REG_INTMR */
{
0x05
,
0x00
},
/* REG_NCPCTRL */
{
0x06
,
0x00
},
/* REG_LDOCTL */
{
0x07
,
0x60
},
/* REG_HPPLLCTL */
{
0x08
,
0x00
},
/* REG_LPPLLCTL */
{
0x09
,
0x4A
},
/* REG_LPPLLDIV */
{
0x0A
,
0x00
},
/* REG_AMICBCTL */
{
0x0B
,
0x00
},
/* REG_DMICBCTL */
{
0x0C
,
0x00
},
/* REG_MICLCTL */
{
0x0D
,
0x00
},
/* REG_MICRCTL */
{
0x0E
,
0x00
},
/* REG_MICGAIN */
{
0x0F
,
0x1B
},
/* REG_LINEGAIN */
{
0x10
,
0x00
},
/* REG_HSLCTL */
{
0x11
,
0x00
},
/* REG_HSRCTL */
{
0x12
,
0x00
},
/* REG_HSGAIN */
{
0x13
,
0x00
},
/* REG_EARCTL */
{
0x14
,
0x00
},
/* REG_HFLCTL */
{
0x15
,
0x00
},
/* REG_HFLGAIN */
{
0x16
,
0x00
},
/* REG_HFRCTL */
{
0x17
,
0x00
},
/* REG_HFRGAIN */
{
0x18
,
0x00
},
/* REG_VIBCTLL */
{
0x19
,
0x00
},
/* REG_VIBDATL */
{
0x1A
,
0x00
},
/* REG_VIBCTLR */
{
0x1B
,
0x00
},
/* REG_VIBDATR */
{
0x1C
,
0x00
},
/* REG_HKCTL1 */
{
0x1D
,
0x00
},
/* REG_HKCTL2 */
{
0x1E
,
0x00
},
/* REG_GPOCTL */
{
0x1F
,
0x00
},
/* REG_ALB */
{
0x20
,
0x00
},
/* REG_DLB */
/* 0x28, REG_TRIM1 */
/* 0x29, REG_TRIM2 */
/* 0x2A, REG_TRIM3 */
/* 0x2B, REG_HSOTRIM */
/* 0x2C, REG_HFOTRIM */
{
0x2D
,
0x08
},
/* REG_ACCCTL */
{
0x2E
,
0x00
},
/* REG_STATUS (ro) */
};
struct
reg_default
twl6040_patch
[]
=
{
/* Select I2C bus access to dual access registers */
{
TWL6040_REG_ACCCTL
,
0x09
},
};
static
bool
twl6040_has_vibra
(
struct
device_node
*
node
)
{
#ifdef CONFIG_OF
...
...
@@ -238,6 +286,9 @@ int twl6040_power(struct twl6040 *twl6040, int on)
if
(
twl6040
->
power_count
++
)
goto
out
;
/* Allow writes to the chip */
regcache_cache_only
(
twl6040
->
regmap
,
false
);
if
(
gpio_is_valid
(
twl6040
->
audpwron
))
{
/* use automatic power-up sequence */
ret
=
twl6040_power_up_automatic
(
twl6040
);
...
...
@@ -253,6 +304,10 @@ int twl6040_power(struct twl6040 *twl6040, int on)
goto
out
;
}
}
/* Sync with the HW */
regcache_sync
(
twl6040
->
regmap
);
/* Default PLL configuration after power up */
twl6040
->
pll
=
TWL6040_SYSCLK_SEL_LPPLL
;
twl6040
->
sysclk
=
19200000
;
...
...
@@ -279,6 +334,11 @@ int twl6040_power(struct twl6040 *twl6040, int on)
/* use manual power-down sequence */
twl6040_power_down_manual
(
twl6040
);
}
/* Set regmap to cache only and mark it as dirty */
regcache_cache_only
(
twl6040
->
regmap
,
true
);
regcache_mark_dirty
(
twl6040
->
regmap
);
twl6040
->
sysclk
=
0
;
twl6040
->
mclk
=
0
;
}
...
...
@@ -490,9 +550,24 @@ static bool twl6040_readable_reg(struct device *dev, unsigned int reg)
static
bool
twl6040_volatile_reg
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
TWL6040_REG_VIBCTLL
:
case
TWL6040_REG_VIBCTLR
:
case
TWL6040_REG_INTMR
:
case
TWL6040_REG_ASICID
:
case
TWL6040_REG_ASICREV
:
case
TWL6040_REG_INTID
:
case
TWL6040_REG_LPPLLCTL
:
case
TWL6040_REG_HPPLLCTL
:
case
TWL6040_REG_STATUS
:
return
true
;
default:
return
false
;
}
}
static
bool
twl6040_writeable_reg
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
TWL6040_REG_ASICID
:
case
TWL6040_REG_ASICREV
:
case
TWL6040_REG_STATUS
:
return
false
;
default:
return
true
;
...
...
@@ -502,10 +577,15 @@ static bool twl6040_volatile_reg(struct device *dev, unsigned int reg)
static
struct
regmap_config
twl6040_regmap_config
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
.
reg_defaults
=
twl6040_defaults
,
.
num_reg_defaults
=
ARRAY_SIZE
(
twl6040_defaults
),
.
max_register
=
TWL6040_REG_STATUS
,
/* 0x2e */
.
readable_reg
=
twl6040_readable_reg
,
.
volatile_reg
=
twl6040_volatile_reg
,
.
writeable_reg
=
twl6040_writeable_reg
,
.
cache_type
=
REGCACHE_RBTREE
,
};
...
...
@@ -624,6 +704,8 @@ static int twl6040_probe(struct i2c_client *client,
/* dual-access registers controlled by I2C only */
twl6040_set_bits
(
twl6040
,
TWL6040_REG_ACCCTL
,
TWL6040_I2CSEL
);
regmap_register_patch
(
twl6040
->
regmap
,
twl6040_patch
,
ARRAY_SIZE
(
twl6040_patch
));
/*
* The main functionality of twl6040 to provide audio on OMAP4+ systems.
...
...
@@ -656,6 +738,10 @@ static int twl6040_probe(struct i2c_client *client,
cell
->
name
=
"twl6040-gpo"
;
children
++
;
/* The chip is powered down so mark regmap to cache only and dirty */
regcache_cache_only
(
twl6040
->
regmap
,
true
);
regcache_mark_dirty
(
twl6040
->
regmap
);
ret
=
mfd_add_devices
(
&
client
->
dev
,
-
1
,
twl6040
->
cells
,
children
,
NULL
,
0
,
NULL
);
if
(
ret
)
...
...
include/linux/i2c/twl.h
View file @
09fd19da
...
...
@@ -175,6 +175,9 @@ static inline int twl_class_is_ ##class(void) \
TWL_CLASS_IS
(
4030
,
TWL4030_CLASS_ID
)
TWL_CLASS_IS
(
6030
,
TWL6030_CLASS_ID
)
/* Set the regcache bypass for the regmap associated with the nodule */
int
twl_set_regcache_bypass
(
u8
mod_no
,
bool
enable
);
/*
* Read and write several 8-bit registers at once.
*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment