Immutable branch between MFD and Extcon due for v3.16 merge-window.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.14 (GNU/Linux)
 
 iQIcBAABAgAGBQJTV7vmAAoJEFGvii+H/HdhStcQAIPXONkcTtnRijYYVo4+zMfY
 5lyEc7bpboK3FJW0SrSM3gt6jSjFayz7HN+oVd5ez73XYlKr+X4oap6GD1VnP+r2
 d2kc0ccfRa5oMPdeth0xabwmXnG2Cm3i3EwLGZAjxRAI72nmmTJu08HSWYSw9tBs
 oxKLuuYNhdIRAoEHrA5wyymb4fq2AdQrdNGEXZ9utZEK7z0+DRxD3LxeNEiW8dU2
 pU9XXlEbp9gQKsyiRL+MPxuFH7C7QpaQN1aryKupHEHtuRPjxqIsXETUsmxGt+sQ
 P3jN3FayYRYknqWSda+/lgEjkzw0CgeLFpR13emt5P2K8K8NPcV17mHhggWxFaes
 iGPi9cgotV9X2zxAgayAusunPRHEQ8Yz7bnQsXBuH04CbBgnu53gBUQyELQhJ2xO
 HBG6VVn5kXCpb80OWX/lTefEIN3yfuH15eV/cmBk3Qu6qqVFjCg6cBqi2b5QFPYN
 8ks/58ewbhKqh+T+yr7N70sXIfOF9aBIqREdnlp/uXaCYLkylSNaUPpxZTllDUnE
 QoJVTMwb/BgGKolhpfwva2UkVPt5C50w1+mNLh05d9IMF/C9kyQMcsC7rOa229LU
 XwtDoWFUTMzjNqTRBTLdElfkEnEET07xDvv3SQTAj30eTCaQs0+gxDMNSrDN/0zN
 u6uUTp1grfVVOoz1FPcS
 =q4Ul
 -----END PGP SIGNATURE-----
mergetag object a613b739b8
 type commit
 tag ib-mfd-omap-3.16
 tagger Lee Jones <lee.jones@linaro.org> 1398263769 +0100
 
 Immutable branch between MFD and ARM OMAP due for v3.16 merge-window.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.14 (GNU/Linux)
 
 iQIcBAABAgAGBQJTV9ADAAoJEFGvii+H/HdhPhkP/1Xoc6APceeJaX8jOmx0rxzQ
 PhYl3er5b3eYtxgGR8s8FrdVrYNyEytGZtMoQN3EYhVnq/ZvbPkR8zMruDszUHYP
 PBfcZJi4GBJIAQU30a8Dvla8UtFaph+IoxSd6E4hSIvb+UFjSvi9ZjQYX82gFop4
 TLeAPW4byQP2YKSkDUq5WzzMLbjQ+ZanJSrueYXmu4VOVgtA0+nBWVj5B8PD1m+O
 2Sp2vhdCPCgIsChQZl3i9h2HroUtomnNWeCdv0YzOwISlvUv+aBg7khK35Jtw7v3
 YeAx3YelQ3z2dnFS/ddEvLKthuTV5BfyGq+dJjMwBLrOv81rzHFBYLCRiABB0RgD
 EUEAv3IJ31SpjrsO0uXnGFp69gMsJgOwLRcjM8TfUi+Wd4YQcbl/tCYX2k7voJ6u
 fbpqarr1zgZpV7r1cX2ivsm8VY2bzQ7p2Dh681oQtHyM+RC94dVvGS0cAaVlnhYY
 MtJWEdtpY3hRcx5qVE8+8wf5RYyXjluhme1EGhO8VL13hMw7ofmtfl2OKN4WAsYO
 KIDMTVJ9RneUQQ6FOx270x17Gp01vxoHIV6pBMi7Uo65l7xrs2YEfgUJhp4eCVXT
 dD4appF5q090UwD7lYADztQZ8RB5GLELZH6Vkpw3qPtfqM97zSy9IFMzTxn446ic
 vdktkG6GJab2vg3mLxDf
 =izRQ
 -----END PGP SIGNATURE-----
mergetag object c42ba72ec3
 type commit
 tag ib-mfd-regulator-3.16
 tagger Lee Jones <lee.jones@linaro.org> 1398675220 +0100
 
 Immutable branch between MFD and Regulator due for v3.16 merge-window.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.14 (GNU/Linux)
 
 iQIcBAABAgAGBQJTXhcuAAoJEFGvii+H/HdhoJEQAI15rEldcSpzLCYiinEfiKUI
 d+6zn5Gx6pKtkfCWdplHxM82Fe5H/kbgCLq+SSCQ6DFrOGXC34i4JnmhdCvcaU/K
 OEtXsG1i2PNzJwMFcnXVW5wD6LnS/b+243XtBtfQ887j9A1R2tEM9ka+i5AP3+O2
 NoBT9DshWWnj16CRJbMMFgNqDI6+QUoirgKzOXLp9stuzrThYU7kaluyMmMUREAx
 tXl8jOBH2Nu0YBiVi6Cgn1xNqtX0Snc9UU1QcugJzuPtyseFsQGUp1cP/ahmeP0y
 EFzKoDbKpag1BV/IEsKWfiD6KEEPFd3IUcZugXIhlRKSGsEcIRTeu6PBFMq9FssF
 hfajzbTw7aDFmYq3Ifc4V6MGtalnCoJz0bsM5XA1voWqXJ+9Tqp4p/5xbJVn2ObA
 /e8k5ljeRH+PBuRKrxgmJJUP3n/QXlJMZ+IrI3BTSeMLu2xZ1U95ynbHO8s3Dxdd
 CpX4xbDq82cBn+JNG3K9+l8XTZUdaWwEQ18VylVcbBdEa4jS2lMyYKIFCJiERLNt
 LCD6hzMGjF7/qVeXhi9AyITEe1XrFSjeTv8WH2R3C4vVXLcjQ3bCnWTFlszbGBsK
 /H0dUWg0HofMrR/oATydWtrgj5F+1aEIdZZqDU0hUCvC849c62zprqXUe7TbP6FT
 yvAlikr5PGMIWw89DCn1
 =NGmT
 -----END PGP SIGNATURE-----

Merge branches 'ib-from-asoc-3.16', 'ib-from-pm-3.16', 'ib-from-regulator-3.16', 'ib-mfd-gpio-3.16' and 'ib-mfd-mmc-memstick-3.16', tags 'ib-mfd-extcon-3.16', 'ib-mfd-omap-3.16' and 'ib-mfd-regulator-3.16' into ibs-for-mfd-merged
This commit is contained in:
Lee Jones 2014-06-03 08:08:40 +01:00
54 changed files with 3670 additions and 500 deletions

View File

@ -228,3 +228,22 @@ is the corresponding frequency table helper for the ->target
stage. Just pass the values to this function, and the unsigned int
index returns the number of the frequency table entry which contains
the frequency the CPU shall be set to.
The following macros can be used as iterators over cpufreq_frequency_table:
cpufreq_for_each_entry(pos, table) - iterates over all entries of frequency
table.
cpufreq-for_each_valid_entry(pos, table) - iterates over all entries,
excluding CPUFREQ_ENTRY_INVALID frequencies.
Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and
"table" - the cpufreq_frequency_table * you want to iterate over.
For example:
struct cpufreq_frequency_table *pos, *driver_freq_table;
cpufreq_for_each_entry(pos, driver_freq_table) {
/* Do something with pos */
pos->frequency = ...
}

View File

@ -10,6 +10,9 @@ Optional properties:
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
Sub-nodes:
- codec: Contain the Audio Codec node.
- adc-port: Contain PMIC SSI port number used for ADC.
- dac-port: Contain PMIC SSI port number used for DAC.
- leds : Contain the led nodes and initial register values in property
"led-control". Number of register depends of used IC, for MC13783 is 6,
for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of

View File

@ -1092,20 +1092,21 @@ int da850_register_cpufreq(char *async_clk)
static int da850_round_armrate(struct clk *clk, unsigned long rate)
{
int i, ret = 0, diff;
int ret = 0, diff;
unsigned int best = (unsigned int) -1;
struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
struct cpufreq_frequency_table *pos;
rate /= 1000; /* convert to kHz */
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
diff = table[i].frequency - rate;
cpufreq_for_each_entry(pos, table) {
diff = pos->frequency - rate;
if (diff < 0)
diff = -diff;
if (diff < best) {
best = diff;
ret = table[i].frequency;
ret = pos->frequency;
}
}

View File

@ -46,15 +46,8 @@
static bool is_offset_valid;
static u8 smps_offset;
/*
* Flag to ensure Smartreflex bit in TWL
* being cleared in board file is not overwritten.
*/
static bool __initdata twl_sr_enable_autoinit;
#define TWL4030_DCDC_GLOBAL_CFG 0x06
#define REG_SMPS_OFFSET 0xE0
#define SMARTREFLEX_ENABLE BIT(3)
static unsigned long twl4030_vsel_to_uv(const u8 vsel)
{
@ -251,18 +244,6 @@ int __init omap3_twl_init(void)
if (!cpu_is_omap34xx())
return -ENODEV;
/*
* The smartreflex bit on twl4030 specifies if the setting of voltage
* is done over the I2C_SR path. Since this setting is independent of
* the actual usage of smartreflex AVS module, we enable TWL SR bit
* by default irrespective of whether smartreflex AVS module is enabled
* on the OMAP side or not. This is because without this bit enabled,
* the voltage scaling through vp forceupdate/bypass mechanism of
* voltage scaling will not function on TWL over I2C_SR.
*/
if (!twl_sr_enable_autoinit)
omap3_twl_set_sr_bit(true);
voltdm = voltdm_lookup("mpu_iva");
omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic);
@ -271,44 +252,3 @@ int __init omap3_twl_init(void)
return 0;
}
/**
* omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL
* @enable: enable SR mode in twl or not
*
* If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure
* voltage scaling through OMAP SR works. Else, the smartreflex bit
* on twl4030 is cleared as there are platforms which use OMAP3 and T2 but
* use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct
* Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages,
* in those scenarios this bit is to be cleared (enable = false).
*
* Returns 0 on success, error is returned if I2C read/write fails.
*/
int __init omap3_twl_set_sr_bit(bool enable)
{
u8 temp;
int ret;
if (twl_sr_enable_autoinit)
pr_warning("%s: unexpected multiple calls\n", __func__);
ret = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
TWL4030_DCDC_GLOBAL_CFG);
if (ret)
goto err;
if (enable)
temp |= SMARTREFLEX_ENABLE;
else
temp &= ~SMARTREFLEX_ENABLE;
ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
TWL4030_DCDC_GLOBAL_CFG);
if (!ret) {
twl_sr_enable_autoinit = true;
return 0;
}
err:
pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret);
return ret;
}

View File

@ -213,7 +213,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
{
int i;
struct cpufreq_frequency_table *pos;
struct acpi_processor_performance *perf;
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
@ -223,10 +223,9 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
perf = data->acpi_data;
for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (msr == perf->states[data->freq_table[i].driver_data].status)
return data->freq_table[i].frequency;
}
cpufreq_for_each_entry(pos, data->freq_table)
if (msr == perf->states[pos->driver_data].status)
return pos->frequency;
return data->freq_table[0].frequency;
}

View File

@ -226,22 +226,22 @@ static inline u32 get_table_count(struct cpufreq_frequency_table *table)
/* get the minimum frequency in the cpufreq_frequency_table */
static inline u32 get_table_min(struct cpufreq_frequency_table *table)
{
int i;
struct cpufreq_frequency_table *pos;
uint32_t min_freq = ~0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
if (table[i].frequency < min_freq)
min_freq = table[i].frequency;
cpufreq_for_each_entry(pos, table)
if (pos->frequency < min_freq)
min_freq = pos->frequency;
return min_freq;
}
/* get the maximum frequency in the cpufreq_frequency_table */
static inline u32 get_table_max(struct cpufreq_frequency_table *table)
{
int i;
struct cpufreq_frequency_table *pos;
uint32_t max_freq = 0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
if (table[i].frequency > max_freq)
max_freq = table[i].frequency;
cpufreq_for_each_entry(pos, table)
if (pos->frequency > max_freq)
max_freq = pos->frequency;
return max_freq;
}

View File

@ -237,6 +237,17 @@ void cpufreq_cpu_put(struct cpufreq_policy *policy)
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
bool cpufreq_next_valid(struct cpufreq_frequency_table **pos)
{
while ((*pos)->frequency != CPUFREQ_TABLE_END)
if ((*pos)->frequency != CPUFREQ_ENTRY_INVALID)
return true;
else
(*pos)++;
return false;
}
EXPORT_SYMBOL_GPL(cpufreq_next_valid);
/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
*********************************************************************/

View File

@ -182,11 +182,11 @@ static void cpufreq_stats_free_table(unsigned int cpu)
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
{
unsigned int i, j, count = 0, ret = 0;
unsigned int i, count = 0, ret = 0;
struct cpufreq_stats *stat;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
struct cpufreq_frequency_table *table;
struct cpufreq_frequency_table *pos, *table;
table = cpufreq_frequency_get_table(cpu);
if (unlikely(!table))
@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
stat->cpu = cpu;
per_cpu(cpufreq_stats_table, cpu) = stat;
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table)
count++;
}
alloc_size = count * sizeof(int) + count * sizeof(u64);
@ -228,15 +224,11 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat->trans_table = stat->freq_table + count;
#endif
j = 0;
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
if (freq_table_get_index(stat, freq) == -1)
stat->freq_table[j++] = freq;
}
stat->state_num = j;
i = 0;
cpufreq_for_each_valid_entry(pos, table)
if (freq_table_get_index(stat, pos->frequency) == -1)
stat->freq_table[i++] = pos->frequency;
stat->state_num = i;
spin_lock(&cpufreq_stats_lock);
stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur);

View File

@ -45,7 +45,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = {
static int dbx500_cpufreq_probe(struct platform_device *pdev)
{
int i = 0;
struct cpufreq_frequency_table *pos;
freq_table = dev_get_platdata(&pdev->dev);
if (!freq_table) {
@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev)
}
pr_info("dbx500-cpufreq: Available frequencies:\n");
while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
i++;
}
cpufreq_for_each_entry(pos, freq_table)
pr_info(" %d Mhz\n", pos->frequency / 1000);
return cpufreq_register_driver(&dbx500_cpufreq_driver);
}

View File

@ -147,7 +147,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = &cpu_data(0);
unsigned int i;
struct cpufreq_frequency_table *pos;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
@ -159,10 +159,9 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
max_freq = elanfreq_get_cpu_frequency(0);
/* table init */
for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
cpufreq_for_each_entry(pos, elanfreq_table)
if (pos->frequency > max_freq)
pos->frequency = CPUFREQ_ENTRY_INVALID;
/* cpuinfo and default policy values */
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;

View File

@ -29,17 +29,16 @@ static unsigned int locking_frequency;
static int exynos_cpufreq_get_index(unsigned int freq)
{
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
int index;
struct cpufreq_frequency_table *pos;
for (index = 0;
freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
if (freq_table[index].frequency == freq)
cpufreq_for_each_entry(pos, freq_table)
if (pos->frequency == freq)
break;
if (freq_table[index].frequency == CPUFREQ_TABLE_END)
if (pos->frequency == CPUFREQ_TABLE_END)
return -EINVAL;
return index;
return pos - freq_table;
}
static int exynos_cpufreq_scale(unsigned int target_freq)

View File

@ -114,25 +114,23 @@ static struct cpufreq_freqs freqs;
static int init_div_table(void)
{
struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table;
unsigned int tmp, clk_div, ema_div, freq, volt_id;
int i = 0;
struct dev_pm_opp *opp;
rcu_read_lock();
for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
cpufreq_for_each_entry(pos, freq_tbl) {
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
freq_tbl[i].frequency * 1000, true);
pos->frequency * 1000, true);
if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(dvfs_info->dev,
"failed to find valid OPP for %u KHZ\n",
freq_tbl[i].frequency);
pos->frequency);
return PTR_ERR(opp);
}
freq = freq_tbl[i].frequency / 1000; /* In MHZ */
freq = pos->frequency / 1000; /* In MHZ */
clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
<< P0_7_CPUCLKDEV_SHIFT;
clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
@ -157,7 +155,8 @@ static int init_div_table(void)
tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
| ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i);
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
(pos - freq_tbl));
}
rcu_read_unlock();
@ -166,8 +165,9 @@ static int init_div_table(void)
static void exynos_enable_dvfs(unsigned int cur_frequency)
{
unsigned int tmp, i, cpu;
unsigned int tmp, cpu;
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
struct cpufreq_frequency_table *pos;
/* Disable DVFS */
__raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
@ -182,15 +182,15 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
/* Set initial performance index */
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
if (freq_table[i].frequency == cur_frequency)
cpufreq_for_each_entry(pos, freq_table)
if (pos->frequency == cur_frequency)
break;
if (freq_table[i].frequency == CPUFREQ_TABLE_END) {
if (pos->frequency == CPUFREQ_TABLE_END) {
dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
/* Assign the highest frequency */
i = 0;
cur_frequency = freq_table[i].frequency;
pos = freq_table;
cur_frequency = pos->frequency;
}
dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
@ -199,7 +199,7 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
tmp |= (i << C0_3_PSTATE_NEW_SHIFT);
tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
}

View File

@ -21,22 +21,19 @@
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
struct cpufreq_frequency_table *pos;
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
unsigned int i;
unsigned int freq;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) {
pr_debug("table entry %u is invalid, skipping\n", i);
cpufreq_for_each_valid_entry(pos, table) {
freq = pos->frequency;
continue;
}
if (!cpufreq_boost_enabled()
&& (table[i].flags & CPUFREQ_BOOST_FREQ))
&& (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
pr_debug("table entry %u: %u kHz\n", i, freq);
pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
if (freq < min_freq)
min_freq = freq;
if (freq > max_freq)
@ -57,7 +54,8 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
unsigned int next_larger = ~0, freq, i = 0;
struct cpufreq_frequency_table *pos;
unsigned int freq, next_larger = ~0;
bool found = false;
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
@ -65,9 +63,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
cpufreq_verify_within_cpu_limits(policy);
for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) {
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table) {
freq = pos->frequency;
if ((freq >= policy->min) && (freq <= policy->max)) {
found = true;
break;
@ -118,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
.driver_data = ~0,
.frequency = 0,
};
unsigned int i;
struct cpufreq_frequency_table *pos;
unsigned int freq, i = 0;
pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
target_freq, relation, policy->cpu);
@ -132,10 +131,10 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
break;
}
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table) {
freq = pos->frequency;
i = pos - table;
if ((freq < policy->min) || (freq > policy->max))
continue;
switch (relation) {
@ -184,8 +183,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
unsigned int freq)
{
struct cpufreq_frequency_table *table;
int i;
struct cpufreq_frequency_table *pos, *table;
table = cpufreq_frequency_get_table(policy->cpu);
if (unlikely(!table)) {
@ -193,10 +191,9 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
return -ENOENT;
}
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (table[i].frequency == freq)
return i;
}
cpufreq_for_each_valid_entry(pos, table)
if (pos->frequency == freq)
return pos - table;
return -EINVAL;
}
@ -208,16 +205,13 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
bool show_boost)
{
unsigned int i = 0;
ssize_t count = 0;
struct cpufreq_frequency_table *table = policy->freq_table;
struct cpufreq_frequency_table *pos, *table = policy->freq_table;
if (!table)
return -ENODEV;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table) {
/*
* show_boost = true and driver_data = BOOST freq
* display BOOST freqs
@ -229,10 +223,10 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
* show_boost = false and driver_data != BOOST freq
* display NON BOOST freqs
*/
if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ))
if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
count += sprintf(&buf[count], "%d ", table[i].frequency);
count += sprintf(&buf[count], "%d ", pos->frequency);
}
count += sprintf(&buf[count], "\n");

View File

@ -530,6 +530,7 @@ static int longhaul_get_ranges(void)
static void longhaul_setup_voltagescaling(void)
{
struct cpufreq_frequency_table *freq_pos;
union msr_longhaul longhaul;
struct mV_pos minvid, maxvid, vid;
unsigned int j, speed, pos, kHz_step, numvscales;
@ -608,18 +609,16 @@ static void longhaul_setup_voltagescaling(void)
/* Calculate kHz for one voltage step */
kHz_step = (highest_speed - min_vid_speed) / numvscales;
j = 0;
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
speed = longhaul_table[j].frequency;
cpufreq_for_each_entry(freq_pos, longhaul_table) {
speed = freq_pos->frequency;
if (speed > min_vid_speed)
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
else
pos = minvid.pos;
longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8;
freq_pos->driver_data |= mV_vrm_table[pos] << 8;
vid = vrm_mV_table[mV_vrm_table[pos]];
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
speed, j, vid.mV);
j++;
speed, (int)(freq_pos - longhaul_table), vid.mV);
}
can_scale_voltage = 1;

View File

@ -136,9 +136,10 @@ void restore_astate(int cpu)
static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
const u32 *max_freqp;
u32 max_freq;
int i, cur_astate;
int cur_astate;
struct resource res;
struct device_node *cpu, *dn;
int err = -ENODEV;
@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n");
/* initialize frequency table */
for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
pas_freqs[i].frequency =
get_astate_freq(pas_freqs[i].driver_data) * 100000;
pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
cpufreq_for_each_entry(pos, pas_freqs) {
pos->frequency = get_astate_freq(pos->driver_data) * 100000;
pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency);
}
cur_astate = get_cur_astate(policy->cpu);

View File

@ -151,6 +151,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
unsigned int i, f;
unsigned khz;
@ -168,12 +169,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
}
}
if (param_max_multiplier) {
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
if (clock_ratio[i].driver_data == param_max_multiplier) {
cpufreq_for_each_entry(pos, clock_ratio)
if (pos->driver_data == param_max_multiplier) {
max_multiplier = param_max_multiplier;
goto have_max_multiplier;
}
}
printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
return -EINVAL;
}
@ -201,12 +201,12 @@ have_busfreq:
param_busfreq = busfreq * 10;
/* table init */
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
f = clock_ratio[i].driver_data;
cpufreq_for_each_entry(pos, clock_ratio) {
f = pos->driver_data;
if (f > max_multiplier)
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
pos->frequency = CPUFREQ_ENTRY_INVALID;
else
clock_ratio[i].frequency = busfreq * f;
pos->frequency = busfreq * f;
}
/* cpuinfo and default policy values */

View File

@ -67,9 +67,10 @@ static int set_pmode(unsigned int cpu, unsigned int slow_mode)
static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
const u32 *max_freqp;
u32 max_freq;
int i, cur_pmode;
int cur_pmode;
struct device_node *cpu;
cpu = of_get_cpu_node(policy->cpu, NULL);
@ -102,9 +103,9 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n");
/* initialize frequency table */
for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
cpufreq_for_each_entry(pos, cbe_freqs) {
pos->frequency = max_freq / pos->driver_data;
pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
}
/* if DEBUG is enabled set_pmode() measures the latency

View File

@ -266,7 +266,7 @@ out:
static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
{
int count, v, i, found;
struct cpufreq_frequency_table *freq;
struct cpufreq_frequency_table *pos;
struct s3c2416_dvfs *dvfs;
count = regulator_count_voltages(s3c_freq->vddarm);
@ -275,12 +275,11 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
return;
}
freq = s3c_freq->freq_table;
while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
continue;
if (!count)
goto out;
dvfs = &s3c2416_dvfs_table[freq->driver_data];
cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) {
dvfs = &s3c2416_dvfs_table[pos->driver_data];
found = 0;
/* Check only the min-voltage, more is always ok on S3C2416 */
@ -292,13 +291,12 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
if (!found) {
pr_debug("cpufreq: %dkHz unsupported by regulator\n",
freq->frequency);
freq->frequency = CPUFREQ_ENTRY_INVALID;
}
freq++;
pos->frequency);
pos->frequency = CPUFREQ_ENTRY_INVALID;
}
}
out:
/* Guessed */
s3c_freq->regulator_latency = 1 * 1000 * 1000;
}
@ -338,7 +336,7 @@ static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
struct cpufreq_frequency_table *freq;
struct cpufreq_frequency_table *pos;
struct clk *msysclk;
unsigned long rate;
int ret;
@ -427,31 +425,27 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
s3c_freq->regulator_latency = 0;
#endif
freq = s3c_freq->freq_table;
while (freq->frequency != CPUFREQ_TABLE_END) {
cpufreq_for_each_entry(pos, s3c_freq->freq_table) {
/* special handling for dvs mode */
if (freq->driver_data == 0) {
if (pos->driver_data == 0) {
if (!s3c_freq->hclk) {
pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
freq->frequency);
freq->frequency = CPUFREQ_ENTRY_INVALID;
pos->frequency);
pos->frequency = CPUFREQ_ENTRY_INVALID;
} else {
freq++;
continue;
}
}
/* Check for frequencies we can generate */
rate = clk_round_rate(s3c_freq->armdiv,
freq->frequency * 1000);
pos->frequency * 1000);
rate /= 1000;
if (rate != freq->frequency) {
if (rate != pos->frequency) {
pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
freq->frequency, rate);
freq->frequency = CPUFREQ_ENTRY_INVALID;
pos->frequency, rate);
pos->frequency = CPUFREQ_ENTRY_INVALID;
}
freq++;
}
/* Datasheet says PLL stabalisation time must be at least 300us,

View File

@ -118,11 +118,10 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
pr_err("Unable to check supported voltages\n");
}
freq = s3c64xx_freq_table;
while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
continue;
if (!count)
goto out;
cpufreq_for_each_valid_entry(freq, s3c64xx_freq_table) {
dvfs = &s3c64xx_dvfs_table[freq->driver_data];
found = 0;
@ -137,10 +136,9 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
freq->frequency);
freq->frequency = CPUFREQ_ENTRY_INVALID;
}
freq++;
}
out:
/* Guess based on having to do an I2C/SPI write; in future we
* will be able to query the regulator performance here. */
regulator_latency = 1 * 1000 * 1000;
@ -179,8 +177,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
}
#endif
freq = s3c64xx_freq_table;
while (freq->frequency != CPUFREQ_TABLE_END) {
cpufreq_for_each_entry(freq, s3c64xx_freq_table) {
unsigned long r;
/* Check for frequencies we can generate */
@ -196,8 +193,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
* frequency is the maximum we can support. */
if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000)
freq->frequency = CPUFREQ_ENTRY_INVALID;
freq++;
}
/* Datasheet says PLL stabalisation time (if we were to use

View File

@ -28,13 +28,13 @@ config EXTCON_ADC_JACK
Say Y here to enable extcon device driver based on ADC values.
config EXTCON_MAX14577
tristate "MAX14577 EXTCON Support"
tristate "MAX14577/77836 EXTCON Support"
depends on MFD_MAX14577
select IRQ_DOMAIN
select REGMAP_I2C
help
If you say yes here you get support for the MUIC device of
Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
detector and switch.
config EXTCON_MAX77693

View File

@ -1,8 +1,9 @@
/*
* extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
* extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2013,2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -24,7 +25,6 @@
#include <linux/mfd/max14577-private.h>
#include <linux/extcon.h>
#define DEV_NAME "max14577-muic"
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
enum max14577_muic_adc_debounce_time {
@ -40,6 +40,42 @@ enum max14577_muic_status {
MAX14577_MUIC_STATUS_END,
};
/**
* struct max14577_muic_irq
* @irq: the index of irq list of MUIC device.
* @name: the name of irq.
* @virq: the virtual irq to use irq domain
*/
struct max14577_muic_irq {
unsigned int irq;
const char *name;
unsigned int virq;
};
static struct max14577_muic_irq max14577_muic_irqs[] = {
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
};
static struct max14577_muic_irq max77836_muic_irqs[] = {
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
{ MAX77836_IRQ_INT1_ADC1K, "muic-ADC1K" },
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
{ MAX77836_IRQ_INT2_VIDRM, "muic-VIDRM" },
};
struct max14577_muic_info {
struct device *dev;
struct max14577 *max14577;
@ -48,6 +84,8 @@ struct max14577_muic_info {
int prev_chg_type;
u8 status[MAX14577_MUIC_STATUS_END];
struct max14577_muic_irq *muic_irqs;
unsigned int muic_irqs_num;
bool irq_adc;
bool irq_chg;
struct work_struct irq_work;
@ -74,29 +112,6 @@ enum max14577_muic_cable_group {
MAX14577_CABLE_GROUP_CHG,
};
/**
* struct max14577_muic_irq
* @irq: the index of irq list of MUIC device.
* @name: the name of irq.
* @virq: the virtual irq to use irq domain
*/
struct max14577_muic_irq {
unsigned int irq;
const char *name;
unsigned int virq;
};
static struct max14577_muic_irq muic_irqs[] = {
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
};
/* Define supported accessory type */
enum max14577_muic_acc_type {
MAX14577_MUIC_ADC_GROUND = 0x0,
@ -528,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work)
return;
}
static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
{
struct max14577_muic_info *info = data;
int i, irq_type = -1;
/*
* We may be called multiple times for different nested IRQ-s.
* Including changes in INT1_ADC and INT2_CGHTYP at once.
* However we only need to know whether it was ADC, charger
* or both interrupts so decode IRQ and turn on proper flags.
* Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
* Returns 0 if irq_type does not match registered IRQ for this device type.
*/
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
if (irq == muic_irqs[i].virq)
irq_type = muic_irqs[i].irq;
static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
{
switch (irq_type) {
case MAX14577_IRQ_INT1_ADC:
case MAX14577_IRQ_INT1_ADCLOW:
@ -550,7 +556,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
/* Handle all of accessory except for
type of charger accessory */
info->irq_adc = true;
break;
return 1;
case MAX14577_IRQ_INT2_CHGTYP:
case MAX14577_IRQ_INT2_CHGDETRUN:
case MAX14577_IRQ_INT2_DCDTMR:
@ -558,8 +564,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
case MAX14577_IRQ_INT2_VBVOLT:
/* Handle charger accessory */
info->irq_chg = true;
break;
return 1;
default:
return 0;
}
}
/*
* Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
* Returns 0 if irq_type does not match registered IRQ for this device type.
*/
static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type)
{
/* First check common max14577 interrupts */
if (max14577_parse_irq(info, irq_type))
return 1;
switch (irq_type) {
case MAX77836_IRQ_INT1_ADC1K:
info->irq_adc = true;
return 1;
case MAX77836_IRQ_INT2_VIDRM:
/* Handle charger accessory */
info->irq_chg = true;
return 1;
default:
return 0;
}
}
static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
{
struct max14577_muic_info *info = data;
int i, irq_type = -1;
bool irq_parsed;
/*
* We may be called multiple times for different nested IRQ-s.
* Including changes in INT1_ADC and INT2_CGHTYP at once.
* However we only need to know whether it was ADC, charger
* or both interrupts so decode IRQ and turn on proper flags.
*/
for (i = 0; i < info->muic_irqs_num; i++)
if (irq == info->muic_irqs[i].virq)
irq_type = info->muic_irqs[i].irq;
switch (info->max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
irq_parsed = max77836_parse_irq(info, irq_type);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
irq_parsed = max14577_parse_irq(info, irq_type);
break;
}
if (!irq_parsed) {
dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
irq_type);
return IRQ_HANDLED;
@ -644,9 +704,20 @@ static int max14577_muic_probe(struct platform_device *pdev)
INIT_WORK(&info->irq_work, max14577_muic_irq_work);
switch (max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
info->muic_irqs = max77836_muic_irqs;
info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
info->muic_irqs = max14577_muic_irqs;
info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs);
}
/* Support irq domain for max14577 MUIC device */
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max14577_muic_irq *muic_irq = &muic_irqs[i];
for (i = 0; i < info->muic_irqs_num; i++) {
struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
unsigned int virq = 0;
virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
@ -673,7 +744,8 @@ static int max14577_muic_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
return -ENOMEM;
}
info->edev->name = DEV_NAME;
info->edev->name = dev_name(&pdev->dev);
info->edev->supported_cable = max14577_extcon_cable;
ret = extcon_dev_register(info->edev);
if (ret) {
@ -735,18 +807,26 @@ static int max14577_muic_remove(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id max14577_muic_id[] = {
{ "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },
{ "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },
{ }
};
MODULE_DEVICE_TABLE(platform, max14577_muic_id);
static struct platform_driver max14577_muic_driver = {
.driver = {
.name = DEV_NAME,
.name = "max14577-muic",
.owner = THIS_MODULE,
},
.probe = max14577_muic_probe,
.remove = max14577_muic_remove,
.id_table = max14577_muic_id,
};
module_platform_driver(max14577_muic_driver);
MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:extcon-max14577");

View File

@ -23,7 +23,8 @@
enum { REG_RE, REG_FE, REG_IE };
#define CACHE_NR_REGS 3
#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8)
/* No variant has more than 24 GPIOs */
#define CACHE_NR_BANKS (24 / 8)
struct stmpe_gpio {
struct gpio_chip chip;
@ -31,8 +32,6 @@ struct stmpe_gpio {
struct device *dev;
struct mutex irq_lock;
struct irq_domain *domain;
int irq_base;
unsigned norequest_mask;
/* Caches of interrupt control registers for bus_lock */
@ -311,13 +310,8 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
struct device_node *np)
{
int base = 0;
if (!np)
base = stmpe_gpio->irq_base;
stmpe_gpio->domain = irq_domain_add_simple(np,
stmpe_gpio->chip.ngpio, base,
stmpe_gpio->chip.ngpio, 0,
&stmpe_gpio_irq_simple_ops, stmpe_gpio);
if (!stmpe_gpio->domain) {
dev_err(stmpe_gpio->dev, "failed to create irqdomain\n");
@ -354,7 +348,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
stmpe_gpio->chip.of_node = np;
#endif
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
stmpe_gpio->chip.base = -1;
if (pdata)
stmpe_gpio->norequest_mask = pdata->norequest_mask;
@ -362,9 +356,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
of_property_read_u32(np, "st,norequest-mask",
&stmpe_gpio->norequest_mask);
if (irq >= 0)
stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
else
if (irq < 0)
dev_info(&pdev->dev,
"device configured in no-irq mode; "
"irqs are not available\n");

View File

@ -52,3 +52,13 @@ config MEMSTICK_REALTEK_PCI
To compile this driver as a module, choose M here: the module will
be called rtsx_pci_ms.
config MEMSTICK_REALTEK_USB
tristate "Realtek USB Memstick Card Interface Driver"
depends on MFD_RTSX_USB
help
Say Y here to include driver code to support Memstick card interface
of Realtek RTS5129/39 series USB card reader
To compile this driver as a module, choose M here: the module will
be called rts5139_ms.

View File

@ -6,3 +6,4 @@ obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o
obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o
obj-$(CONFIG_MEMSTICK_R592) += r592.o
obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o
obj-$(CONFIG_MEMSTICK_REALTEK_USB) += rtsx_usb_ms.o

View File

@ -0,0 +1,839 @@
/* Realtek USB Memstick Card Interface driver
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Roger Tseng <rogerable@realtek.com>
*/
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/memstick.h>
#include <linux/kthread.h>
#include <linux/mfd/rtsx_usb.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <asm/unaligned.h>
struct rtsx_usb_ms {
struct platform_device *pdev;
struct rtsx_ucr *ucr;
struct memstick_host *msh;
struct memstick_request *req;
struct mutex host_mutex;
struct work_struct handle_req;
struct task_struct *detect_ms;
struct completion detect_ms_exit;
u8 ssc_depth;
unsigned int clock;
int power_mode;
unsigned char ifmode;
bool eject;
};
static inline struct device *ms_dev(struct rtsx_usb_ms *host)
{
return &(host->pdev->dev);
}
static inline void ms_clear_error(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
rtsx_usb_ep0_write_register(ucr, CARD_STOP,
MS_STOP | MS_CLR_ERR,
MS_STOP | MS_CLR_ERR);
rtsx_usb_clear_dma_err(ucr);
rtsx_usb_clear_fsm_err(ucr);
}
#ifdef DEBUG
static void ms_print_debug_regs(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
u16 i;
u8 *ptr;
/* Print MS host internal registers */
rtsx_usb_init_cmd(ucr);
/* MS_CFG to MS_INT_REG */
for (i = 0xFD40; i <= 0xFD44; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0);
/* CARD_SHARE_MODE to CARD_GPIO */
for (i = 0xFD51; i <= 0xFD56; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0);
/* CARD_PULL_CTLx */
for (i = 0xFD60; i <= 0xFD65; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0);
/* CARD_DATA_SOURCE, CARD_SELECT, CARD_CLK_EN, CARD_PWR_CTL */
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_DATA_SOURCE, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_SELECT, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_CLK_EN, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_PWR_CTL, 0, 0);
rtsx_usb_send_cmd(ucr, MODE_CR, 100);
rtsx_usb_get_rsp(ucr, 21, 100);
ptr = ucr->rsp_buf;
for (i = 0xFD40; i <= 0xFD44; i++)
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
for (i = 0xFD51; i <= 0xFD56; i++)
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
for (i = 0xFD60; i <= 0xFD65; i++)
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_DATA_SOURCE, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_SELECT, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_CLK_EN, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_PWR_CTL, *(ptr++));
}
#else
static void ms_print_debug_regs(struct rtsx_usb_ms *host)
{
}
#endif
static int ms_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_power_on(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(ms_dev(host), "%s\n", __func__);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE,
CARD_SHARE_MASK, CARD_SHARE_MS);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN,
MS_CLK_EN, MS_CLK_EN);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err < 0)
return err;
if (CHECK_PKG(ucr, LQFP48))
err = ms_pull_ctl_enable_lqfp48(ucr);
else
err = ms_pull_ctl_enable_qfn24(ucr);
if (err < 0)
return err;
err = rtsx_usb_write_register(ucr, CARD_PWR_CTL,
POWER_MASK, PARTIAL_POWER_ON);
if (err)
return err;
usleep_range(800, 1000);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
POWER_MASK, POWER_ON);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE,
MS_OUTPUT_EN, MS_OUTPUT_EN);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_power_off(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(ms_dev(host), "%s\n", __func__);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err < 0)
return err;
if (CHECK_PKG(ucr, LQFP48))
return ms_pull_ctl_disable_lqfp48(ucr);
return ms_pull_ctl_disable_qfn24(ucr);
}
static int ms_transfer_data(struct rtsx_usb_ms *host, unsigned char data_dir,
u8 tpc, u8 cfg, struct scatterlist *sg)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
unsigned int length = sg->length;
u16 sec_cnt = (u16)(length / 512);
u8 trans_mode, dma_dir, flag;
unsigned int pipe;
struct memstick_dev *card = host->msh->card;
dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n",
__func__, tpc, (data_dir == READ) ? "READ" : "WRITE",
length);
if (data_dir == READ) {
flag = MODE_CDIR;
dma_dir = DMA_DIR_FROM_CARD;
if (card->id.type != MEMSTICK_TYPE_PRO)
trans_mode = MS_TM_NORMAL_READ;
else
trans_mode = MS_TM_AUTO_READ;
pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN);
} else {
flag = MODE_CDOR;
dma_dir = DMA_DIR_TO_CARD;
if (card->id.type != MEMSTICK_TYPE_PRO)
trans_mode = MS_TM_NORMAL_WRITE;
else
trans_mode = MS_TM_AUTO_WRITE;
pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT);
}
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
if (card->id.type == MEMSTICK_TYPE_PRO) {
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_H,
0xFF, (u8)(sec_cnt >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_L,
0xFF, (u8)sec_cnt);
}
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3,
0xFF, (u8)(length >> 24));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2,
0xFF, (u8)(length >> 16));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1,
0xFF, (u8)(length >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0, 0xFF,
(u8)length);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, RING_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER,
0xFF, MS_TRANSFER_START | trans_mode);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER,
MS_TRANSFER_END, MS_TRANSFER_END);
err = rtsx_usb_send_cmd(ucr, flag | STAGE_MS_STATUS, 100);
if (err)
return err;
err = rtsx_usb_transfer_data(ucr, pipe, sg, length,
1, NULL, 10000);
if (err)
goto err_out;
err = rtsx_usb_get_rsp(ucr, 3, 15000);
if (err)
goto err_out;
if (ucr->rsp_buf[0] & MS_TRANSFER_ERR ||
ucr->rsp_buf[1] & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
err = -EIO;
goto err_out;
}
return 0;
err_out:
ms_clear_error(host);
return err;
}
static int ms_write_bytes(struct rtsx_usb_ms *host, u8 tpc,
u8 cfg, u8 cnt, u8 *data, u8 *int_reg)
{
struct rtsx_ucr *ucr = host->ucr;
int err, i;
dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc);
rtsx_usb_init_cmd(ucr);
for (i = 0; i < cnt; i++)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
PPBUF_BASE2 + i, 0xFF, data[i]);
if (cnt % 2)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
PPBUF_BASE2 + i, 0xFF, 0xFF);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER,
0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER,
MS_TRANSFER_END, MS_TRANSFER_END);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (err)
return err;
err = rtsx_usb_get_rsp(ucr, 2, 5000);
if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) {
u8 val;
rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val);
dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val);
if (int_reg)
*int_reg = val & 0x0F;
ms_print_debug_regs(host);
ms_clear_error(host);
if (!(tpc & 0x08)) {
if (val & MS_CRC16_ERR)
return -EIO;
} else {
if (!(val & 0x80)) {
if (val & (MS_INT_ERR | MS_INT_CMDNK))
return -EIO;
}
}
return -ETIMEDOUT;
}
if (int_reg)
*int_reg = ucr->rsp_buf[1] & 0x0F;
return 0;
}
static int ms_read_bytes(struct rtsx_usb_ms *host, u8 tpc,
u8 cfg, u8 cnt, u8 *data, u8 *int_reg)
{
struct rtsx_ucr *ucr = host->ucr;
int err, i;
u8 *ptr;
dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER,
0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER,
MS_TRANSFER_END, MS_TRANSFER_END);
for (i = 0; i < cnt - 1; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
if (cnt % 2)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0);
else
rtsx_usb_add_cmd(ucr, READ_REG_CMD,
PPBUF_BASE2 + cnt - 1, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (err)
return err;
err = rtsx_usb_get_rsp(ucr, cnt + 2, 5000);
if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) {
u8 val;
rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val);
dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val);
if (int_reg && (host->ifmode != MEMSTICK_SERIAL))
*int_reg = val & 0x0F;
ms_print_debug_regs(host);
ms_clear_error(host);
if (!(tpc & 0x08)) {
if (val & MS_CRC16_ERR)
return -EIO;
} else {
if (!(val & 0x80)) {
if (val & (MS_INT_ERR | MS_INT_CMDNK))
return -EIO;
}
}
return -ETIMEDOUT;
}
ptr = ucr->rsp_buf + 1;
for (i = 0; i < cnt; i++)
data[i] = *ptr++;
if (int_reg && (host->ifmode != MEMSTICK_SERIAL))
*int_reg = *ptr & 0x0F;
return 0;
}
static int rtsx_usb_ms_issue_cmd(struct rtsx_usb_ms *host)
{
struct memstick_request *req = host->req;
int err = 0;
u8 cfg = 0, int_reg;
dev_dbg(ms_dev(host), "%s\n", __func__);
if (req->need_card_int) {
if (host->ifmode != MEMSTICK_SERIAL)
cfg = WAIT_INT;
}
if (req->long_data) {
err = ms_transfer_data(host, req->data_dir,
req->tpc, cfg, &(req->sg));
} else {
if (req->data_dir == READ)
err = ms_read_bytes(host, req->tpc, cfg,
req->data_len, req->data, &int_reg);
else
err = ms_write_bytes(host, req->tpc, cfg,
req->data_len, req->data, &int_reg);
}
if (err < 0)
return err;
if (req->need_card_int) {
if (host->ifmode == MEMSTICK_SERIAL) {
err = ms_read_bytes(host, MS_TPC_GET_INT,
NO_WAIT_INT, 1, &req->int_reg, NULL);
if (err < 0)
return err;
} else {
if (int_reg & MS_INT_CMDNK)
req->int_reg |= MEMSTICK_INT_CMDNAK;
if (int_reg & MS_INT_BREQ)
req->int_reg |= MEMSTICK_INT_BREQ;
if (int_reg & MS_INT_ERR)
req->int_reg |= MEMSTICK_INT_ERR;
if (int_reg & MS_INT_CED)
req->int_reg |= MEMSTICK_INT_CED;
}
dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", req->int_reg);
}
return 0;
}
static void rtsx_usb_ms_handle_req(struct work_struct *work)
{
struct rtsx_usb_ms *host = container_of(work,
struct rtsx_usb_ms, handle_req);
struct rtsx_ucr *ucr = host->ucr;
struct memstick_host *msh = host->msh;
int rc;
if (!host->req) {
do {
rc = memstick_next_req(msh, &host->req);
dev_dbg(ms_dev(host), "next req %d\n", rc);
if (!rc) {
mutex_lock(&ucr->dev_mutex);
if (rtsx_usb_card_exclusive_check(ucr,
RTSX_USB_MS_CARD))
host->req->error = -EIO;
else
host->req->error =
rtsx_usb_ms_issue_cmd(host);
mutex_unlock(&ucr->dev_mutex);
dev_dbg(ms_dev(host), "req result %d\n",
host->req->error);
}
} while (!rc);
}
}
static void rtsx_usb_ms_request(struct memstick_host *msh)
{
struct rtsx_usb_ms *host = memstick_priv(msh);
dev_dbg(ms_dev(host), "--> %s\n", __func__);
if (!host->eject)
schedule_work(&host->handle_req);
}
static int rtsx_usb_ms_set_param(struct memstick_host *msh,
enum memstick_param param, int value)
{
struct rtsx_usb_ms *host = memstick_priv(msh);
struct rtsx_ucr *ucr = host->ucr;
unsigned int clock = 0;
u8 ssc_depth = 0;
int err;
dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
__func__, param, value);
mutex_lock(&ucr->dev_mutex);
err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD);
if (err)
goto out;
switch (param) {
case MEMSTICK_POWER:
if (value == host->power_mode)
break;
if (value == MEMSTICK_POWER_ON) {
pm_runtime_get_sync(ms_dev(host));
err = ms_power_on(host);
} else if (value == MEMSTICK_POWER_OFF) {
err = ms_power_off(host);
if (host->msh->card)
pm_runtime_put_noidle(ms_dev(host));
else
pm_runtime_put(ms_dev(host));
} else
err = -EINVAL;
if (!err)
host->power_mode = value;
break;
case MEMSTICK_INTERFACE:
if (value == MEMSTICK_SERIAL) {
clock = 19000000;
ssc_depth = SSC_DEPTH_512K;
err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A,
MS_BUS_WIDTH_1 | PUSH_TIME_DEFAULT);
if (err < 0)
break;
} else if (value == MEMSTICK_PAR4) {
clock = 39000000;
ssc_depth = SSC_DEPTH_1M;
err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A,
MS_BUS_WIDTH_4 | PUSH_TIME_ODD |
MS_NO_CHECK_INT);
if (err < 0)
break;
} else {
err = -EINVAL;
break;
}
err = rtsx_usb_switch_clock(ucr, clock,
ssc_depth, false, true, false);
if (err < 0) {
dev_dbg(ms_dev(host), "switch clock failed\n");
break;
}
host->ssc_depth = ssc_depth;
host->clock = clock;
host->ifmode = value;
break;
default:
err = -EINVAL;
break;
}
out:
mutex_unlock(&ucr->dev_mutex);
/* power-on delay */
if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON)
usleep_range(10000, 12000);
dev_dbg(ms_dev(host), "%s: return = %d\n", __func__, err);
return err;
}
#ifdef CONFIG_PM_SLEEP
static int rtsx_usb_ms_suspend(struct device *dev)
{
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
struct memstick_host *msh = host->msh;
dev_dbg(ms_dev(host), "--> %s\n", __func__);
memstick_suspend_host(msh);
return 0;
}
static int rtsx_usb_ms_resume(struct device *dev)
{
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
struct memstick_host *msh = host->msh;
dev_dbg(ms_dev(host), "--> %s\n", __func__);
memstick_resume_host(msh);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
/*
* Thread function of ms card slot detection. The thread starts right after
* successful host addition. It stops while the driver removal function sets
* host->eject true.
*/
static int rtsx_usb_detect_ms_card(void *__host)
{
struct rtsx_usb_ms *host = (struct rtsx_usb_ms *)__host;
struct rtsx_ucr *ucr = host->ucr;
u8 val = 0;
int err;
for (;;) {
mutex_lock(&ucr->dev_mutex);
/* Check pending MS card changes */
err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val);
if (err) {
mutex_unlock(&ucr->dev_mutex);
goto poll_again;
}
/* Clear the pending */
rtsx_usb_write_register(ucr, CARD_INT_PEND,
XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
mutex_unlock(&ucr->dev_mutex);
if (val & MS_INT) {
dev_dbg(ms_dev(host), "MS slot change detected\n");
memstick_detect_change(host->msh);
}
poll_again:
if (host->eject)
break;
msleep(1000);
}
complete(&host->detect_ms_exit);
return 0;
}
static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
{
struct memstick_host *msh;
struct rtsx_usb_ms *host;
struct rtsx_ucr *ucr;
int err;
ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
if (!ucr)
return -ENXIO;
dev_dbg(&(pdev->dev),
"Realtek USB Memstick controller found\n");
msh = memstick_alloc_host(sizeof(*host), &pdev->dev);
if (!msh)
return -ENOMEM;
host = memstick_priv(msh);
host->ucr = ucr;
host->msh = msh;
host->pdev = pdev;
host->power_mode = MEMSTICK_POWER_OFF;
platform_set_drvdata(pdev, host);
mutex_init(&host->host_mutex);
INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req);
init_completion(&host->detect_ms_exit);
host->detect_ms = kthread_create(rtsx_usb_detect_ms_card, host,
"rtsx_usb_ms_%d", pdev->id);
if (IS_ERR(host->detect_ms)) {
dev_dbg(&(pdev->dev),
"Unable to create polling thread.\n");
err = PTR_ERR(host->detect_ms);
goto err_out;
}
msh->request = rtsx_usb_ms_request;
msh->set_param = rtsx_usb_ms_set_param;
msh->caps = MEMSTICK_CAP_PAR4;
pm_runtime_enable(&pdev->dev);
err = memstick_add_host(msh);
if (err)
goto err_out;
wake_up_process(host->detect_ms);
return 0;
err_out:
memstick_free_host(msh);
return err;
}
static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
{
struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
struct memstick_host *msh;
int err;
msh = host->msh;
host->eject = true;
cancel_work_sync(&host->handle_req);
mutex_lock(&host->host_mutex);
if (host->req) {
dev_dbg(&(pdev->dev),
"%s: Controller removed during transfer\n",
dev_name(&msh->dev));
host->req->error = -ENOMEDIUM;
do {
err = memstick_next_req(msh, &host->req);
if (!err)
host->req->error = -ENOMEDIUM;
} while (!err);
}
mutex_unlock(&host->host_mutex);
wait_for_completion(&host->detect_ms_exit);
memstick_remove_host(msh);
memstick_free_host(msh);
/* Balance possible unbalanced usage count
* e.g. unconditional module removal
*/
if (pm_runtime_active(ms_dev(host)))
pm_runtime_put(ms_dev(host));
pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
dev_dbg(&(pdev->dev),
": Realtek USB Memstick controller has been removed\n");
return 0;
}
static SIMPLE_DEV_PM_OPS(rtsx_usb_ms_pm_ops,
rtsx_usb_ms_suspend, rtsx_usb_ms_resume);
static struct platform_device_id rtsx_usb_ms_ids[] = {
{
.name = "rtsx_usb_ms",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids);
static struct platform_driver rtsx_usb_ms_driver = {
.probe = rtsx_usb_ms_drv_probe,
.remove = rtsx_usb_ms_drv_remove,
.id_table = rtsx_usb_ms_ids,
.driver = {
.owner = THIS_MODULE,
.name = "rtsx_usb_ms",
.pm = &rtsx_usb_ms_pm_ops,
},
};
module_platform_driver(rtsx_usb_ms_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
MODULE_DESCRIPTION("Realtek USB Memstick Card Host Driver");

View File

@ -331,15 +331,15 @@ config MFD_88PM860X
battery-charger under the corresponding menus.
config MFD_MAX14577
bool "Maxim Semiconductor MAX14577 MUIC + Charger Support"
bool "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support"
depends on I2C=y
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
select IRQ_DOMAIN
help
Say yes here to add support for Maxim Semiconductor MAX14577.
This is a Micro-USB IC with Charger controls on chip.
Say yes here to add support for Maxim Semiconductor MAX14577 and
MAX77836 Micro-USB ICs with battery charger.
This driver provides common support for accessing the device;
additional drivers must be enabled in order to use the functionality
of the device.
@ -675,6 +675,7 @@ config MFD_DB8500_PRCMU
config MFD_STMPE
bool "STMicroelectronics STMPE"
depends on (I2C=y || SPI_MASTER=y)
depends on OF
select MFD_CORE
help
Support for the STMPE family of I/O Expanders from

View File

@ -508,19 +508,31 @@ int arizona_of_get_type(struct device *dev)
}
EXPORT_SYMBOL_GPL(arizona_of_get_type);
int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
bool mandatory)
{
int gpio;
gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
if (gpio < 0) {
if (mandatory)
dev_err(arizona->dev,
"Mandatory DT gpio %s missing/malformed: %d\n",
prop, gpio);
gpio = 0;
}
return gpio;
}
EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
static int arizona_of_get_core_pdata(struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
int ret, i;
arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
"wlf,reset", 0);
if (arizona->pdata.reset < 0)
arizona->pdata.reset = 0;
arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node,
"wlf,ldoena", 0);
if (arizona->pdata.ldoena < 0)
arizona->pdata.ldoena = 0;
pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
ret = of_property_read_u32_array(arizona->dev->of_node,
"wlf,gpio-defaults",
@ -652,6 +664,9 @@ int arizona_dev_init(struct arizona *arizona)
return -EINVAL;
}
/* Mark DCVDD as external, LDO1 driver will clear if internal */
arizona->external_dcvdd = true;
ret = mfd_add_devices(arizona->dev, -1, early_devs,
ARRAY_SIZE(early_devs), NULL, 0, NULL);
if (ret != 0) {
@ -851,14 +866,6 @@ int arizona_dev_init(struct arizona *arizona)
arizona->pdata.gpio_defaults[i]);
}
/*
* LDO1 can only be used to supply DCVDD so if it has no
* consumers then DCVDD is supplied externally.
*/
if (arizona->pdata.ldo1 &&
arizona->pdata.ldo1->num_consumer_supplies == 0)
arizona->external_dcvdd = true;
pm_runtime_set_autosuspend_delay(arizona->dev, 100);
pm_runtime_use_autosuspend(arizona->dev);
pm_runtime_enable(arizona->dev);

View File

@ -1734,18 +1734,17 @@ static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
static long round_armss_rate(unsigned long rate)
{
struct cpufreq_frequency_table *pos;
long freq = 0;
int i = 0;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
freq = db8500_cpufreq_table[i].frequency;
cpufreq_for_each_entry(pos, db8500_cpufreq_table) {
freq = pos->frequency;
if (freq == rate)
break;
i++;
}
/* Return the last valid value, even if a match was not found. */
@ -1886,23 +1885,21 @@ static void set_clock_rate(u8 clock, unsigned long rate)
static int set_armss_rate(unsigned long rate)
{
int i = 0;
struct cpufreq_frequency_table *pos;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
if (db8500_cpufreq_table[i].frequency == rate)
cpufreq_for_each_entry(pos, db8500_cpufreq_table)
if (pos->frequency == rate)
break;
i++;
}
if (db8500_cpufreq_table[i].frequency != rate)
if (pos->frequency != rate)
return -EINVAL;
/* Set the new arm opp. */
return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].driver_data);
return db8500_prcmu_set_arm_opp(pos->driver_data);
}
static int set_plldsi_rate(unsigned long rate)

View File

@ -1,7 +1,7 @@
/*
* max14577.c - mfd core driver for the Maxim 14577
* max14577.c - mfd core driver for the Maxim 14577/77836
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
@ -21,6 +21,7 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max14577.h>
#include <linux/mfd/max14577-private.h>
@ -37,7 +38,38 @@ static struct mfd_cell max14577_devs[] = {
{ .name = "max14577-charger", },
};
static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
static struct mfd_cell max77836_devs[] = {
{
.name = "max77836-muic",
.of_compatible = "maxim,max77836-muic",
},
{
.name = "max77836-regulator",
.of_compatible = "maxim,max77836-regulator",
},
{
.name = "max77836-charger",
.of_compatible = "maxim,max77836-charger",
},
{
.name = "max77836-battery",
.of_compatible = "maxim,max77836-battery",
},
};
static struct of_device_id max14577_dt_match[] = {
{
.compatible = "maxim,max14577",
.data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
},
{
.compatible = "maxim,max77836",
.data = (void *)MAXIM_DEVICE_TYPE_MAX77836,
},
{},
};
static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3:
@ -48,49 +80,221 @@ static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
return false;
}
static const struct regmap_config max14577_regmap_config = {
static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg)
{
/* Any max14577 volatile registers are also max77836 volatile. */
if (max14577_muic_volatile_reg(dev, reg))
return true;
switch (reg) {
case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB:
case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB:
case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L:
case MAX77836_PMIC_REG_INTSRC:
case MAX77836_PMIC_REG_TOPSYS_INT:
case MAX77836_PMIC_REG_TOPSYS_STAT:
return true;
default:
break;
}
return false;
}
static const struct regmap_config max14577_muic_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = max14577_volatile_reg,
.volatile_reg = max14577_muic_volatile_reg,
.max_register = MAX14577_REG_END,
};
static const struct regmap_config max77836_pmic_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = max77836_muic_volatile_reg,
.max_register = MAX77836_PMIC_REG_END,
};
static const struct regmap_irq max14577_irqs[] = {
/* INT1 interrupts */
{ .reg_offset = 0, .mask = INT1_ADC_MASK, },
{ .reg_offset = 0, .mask = INT1_ADCLOW_MASK, },
{ .reg_offset = 0, .mask = INT1_ADCERR_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
/* INT2 interrupts */
{ .reg_offset = 1, .mask = INT2_CHGTYP_MASK, },
{ .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, },
{ .reg_offset = 1, .mask = INT2_DCDTMR_MASK, },
{ .reg_offset = 1, .mask = INT2_DBCHG_MASK, },
{ .reg_offset = 1, .mask = INT2_VBVOLT_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
/* INT3 interrupts */
{ .reg_offset = 2, .mask = INT3_EOC_MASK, },
{ .reg_offset = 2, .mask = INT3_CGMBC_MASK, },
{ .reg_offset = 2, .mask = INT3_OVP_MASK, },
{ .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
};
static const struct regmap_irq_chip max14577_irq_chip = {
.name = "max14577",
.status_base = MAX14577_REG_INT1,
.mask_base = MAX14577_REG_INTMASK1,
.mask_invert = 1,
.mask_invert = true,
.num_regs = 3,
.irqs = max14577_irqs,
.num_irqs = ARRAY_SIZE(max14577_irqs),
};
static const struct regmap_irq max77836_muic_irqs[] = {
/* INT1 interrupts */
{ .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
{ .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, },
/* INT2 interrupts */
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
{ .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, },
/* INT3 interrupts */
{ .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
};
static const struct regmap_irq_chip max77836_muic_irq_chip = {
.name = "max77836-muic",
.status_base = MAX14577_REG_INT1,
.mask_base = MAX14577_REG_INTMASK1,
.mask_invert = true,
.num_regs = 3,
.irqs = max77836_muic_irqs,
.num_irqs = ARRAY_SIZE(max77836_muic_irqs),
};
static const struct regmap_irq max77836_pmic_irqs[] = {
{ .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, },
{ .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, },
};
static const struct regmap_irq_chip max77836_pmic_irq_chip = {
.name = "max77836-pmic",
.status_base = MAX77836_PMIC_REG_TOPSYS_INT,
.mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK,
.mask_invert = false,
.num_regs = 1,
.irqs = max77836_pmic_irqs,
.num_irqs = ARRAY_SIZE(max77836_pmic_irqs),
};
static void max14577_print_dev_type(struct max14577 *max14577)
{
u8 reg_data, vendor_id, device_id;
int ret;
ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
&reg_data);
if (ret) {
dev_err(max14577->dev,
"Failed to read DEVICEID register: %d\n", ret);
return;
}
vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
DEVID_VENDORID_SHIFT);
device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
DEVID_DEVICEID_SHIFT);
dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n",
max14577->dev_type, device_id, vendor_id);
}
/*
* Max77836 specific initialization code for driver probe.
* Adds new I2C dummy device, regmap and regmap IRQ chip.
* Unmasks Interrupt Source register.
*
* On success returns 0.
* On failure returns errno and reverts any changes done so far (e.g. remove
* I2C dummy device), except masking the INT SRC register.
*/
static int max77836_init(struct max14577 *max14577)
{
int ret;
u8 intsrc_mask;
max14577->i2c_pmic = i2c_new_dummy(max14577->i2c->adapter,
I2C_ADDR_PMIC);
if (!max14577->i2c_pmic) {
dev_err(max14577->dev, "Failed to register PMIC I2C device\n");
return -ENODEV;
}
i2c_set_clientdata(max14577->i2c_pmic, max14577);
max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic,
&max77836_pmic_regmap_config);
if (IS_ERR(max14577->regmap_pmic)) {
ret = PTR_ERR(max14577->regmap_pmic);
dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n",
ret);
goto err;
}
/* Un-mask MAX77836 Interrupt Source register */
ret = max14577_read_reg(max14577->regmap_pmic,
MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask);
if (ret < 0) {
dev_err(max14577->dev, "Failed to read PMIC register\n");
goto err;
}
intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK);
intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK);
ret = max14577_write_reg(max14577->regmap_pmic,
MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask);
if (ret < 0) {
dev_err(max14577->dev, "Failed to write PMIC register\n");
goto err;
}
ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED,
0, &max77836_pmic_irq_chip,
&max14577->irq_data_pmic);
if (ret != 0) {
dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n",
max14577->irq, ret);
goto err;
}
return 0;
err:
i2c_unregister_device(max14577->i2c_pmic);
return ret;
}
/*
* Max77836 specific de-initialization code for driver remove.
*/
static void max77836_remove(struct max14577 *max14577)
{
regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic);
i2c_unregister_device(max14577->i2c_pmic);
}
static int max14577_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max14577 *max14577;
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct device_node *np = i2c->dev.of_node;
u8 reg_data;
int ret = 0;
const struct regmap_irq_chip *irq_chip;
struct mfd_cell *mfd_devs;
unsigned int mfd_devs_size;
int irq_flags;
if (np) {
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
@ -113,7 +317,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
max14577->i2c = i2c;
max14577->irq = i2c->irq;
max14577->regmap = devm_regmap_init_i2c(i2c, &max14577_regmap_config);
max14577->regmap = devm_regmap_init_i2c(i2c,
&max14577_muic_regmap_config);
if (IS_ERR(max14577->regmap)) {
ret = PTR_ERR(max14577->regmap);
dev_err(max14577->dev, "Failed to allocate register map: %d\n",
@ -121,23 +326,36 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
&reg_data);
if (ret) {
dev_err(max14577->dev, "Device not found on this channel: %d\n",
ret);
return ret;
if (np) {
const struct of_device_id *of_id;
of_id = of_match_device(max14577_dt_match, &i2c->dev);
if (of_id)
max14577->dev_type = (unsigned int)of_id->data;
} else {
max14577->dev_type = id->driver_data;
}
max14577_print_dev_type(max14577);
switch (max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
irq_chip = &max77836_muic_irq_chip;
mfd_devs = max77836_devs;
mfd_devs_size = ARRAY_SIZE(max77836_devs);
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
irq_chip = &max14577_irq_chip;
mfd_devs = max14577_devs;
mfd_devs_size = ARRAY_SIZE(max14577_devs);
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
break;
}
max14577->vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
DEVID_VENDORID_SHIFT);
max14577->device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
DEVID_DEVICEID_SHIFT);
dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n",
max14577->device_id, max14577->vendor_id);
ret = regmap_add_irq_chip(max14577->regmap, max14577->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
&max14577_irq_chip,
irq_flags, 0, irq_chip,
&max14577->irq_data);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
@ -145,8 +363,15 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = mfd_add_devices(max14577->dev, -1, max14577_devs,
ARRAY_SIZE(max14577_devs), NULL, 0,
/* Max77836 specific initialization code (additional regmap) */
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) {
ret = max77836_init(max14577);
if (ret < 0)
goto err_max77836;
}
ret = mfd_add_devices(max14577->dev, -1, mfd_devs,
mfd_devs_size, NULL, 0,
regmap_irq_get_domain(max14577->irq_data));
if (ret < 0)
goto err_mfd;
@ -156,6 +381,9 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return 0;
err_mfd:
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
max77836_remove(max14577);
err_max77836:
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
return ret;
@ -167,12 +395,15 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(max14577->dev);
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
max77836_remove(max14577);
return 0;
}
static const struct i2c_device_id max14577_i2c_id[] = {
{ "max14577", 0 },
{ "max14577", MAXIM_DEVICE_TYPE_MAX14577, },
{ "max77836", MAXIM_DEVICE_TYPE_MAX77836, },
{ }
};
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
@ -215,11 +446,6 @@ static int max14577_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
static struct of_device_id max14577_dt_match[] = {
{ .compatible = "maxim,max14577", },
{},
};
static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume);
static struct i2c_driver max14577_i2c_driver = {
@ -236,6 +462,9 @@ static struct i2c_driver max14577_i2c_driver = {
static int __init max14577_i2c_init(void)
{
BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM);
BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM);
return i2c_add_driver(&max14577_i2c_driver);
}
subsys_initcall(max14577_i2c_init);
@ -247,5 +476,5 @@ static void __exit max14577_i2c_exit(void)
module_exit(max14577_i2c_exit);
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver");
MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
MODULE_LICENSE("GPL");

View File

@ -673,9 +673,13 @@ int mc13xxx_common_init(struct device *dev)
if (mc13xxx->flags & MC13XXX_USE_ADC)
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
if (mc13xxx->flags & MC13XXX_USE_CODEC)
if (mc13xxx->flags & MC13XXX_USE_CODEC) {
if (pdata)
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
pdata->codec, sizeof(*pdata->codec));
else
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
}
if (mc13xxx->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");

View File

@ -67,7 +67,7 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
add_timer(&ucr->sg_timer);
usb_sg_wait(&ucr->current_sg);
del_timer(&ucr->sg_timer);
del_timer_sync(&ucr->sg_timer);
if (act_len)
*act_len = ucr->current_sg.bytes;
@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf,
if (ret)
goto out_init_fail;
/* initialize USB SG transfer timer */
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
if (ret)
goto out_init_fail;
/* initialize USB SG transfer timer */
init_timer(&ucr->sg_timer);
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
#ifdef CONFIG_PM
intf->needs_remote_wakeup = 1;
usb_enable_autosuspend(usb_dev);
@ -687,9 +687,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n",
__func__, message.event);
/*
* Call to make sure LED is off during suspend to save more power.
* It is NOT a permanent state and could be turned on anytime later.
* Thus no need to call turn_on when resunming.
*/
mutex_lock(&ucr->dev_mutex);
rtsx_usb_turn_off_led(ucr);
mutex_unlock(&ucr->dev_mutex);
return 0;
}

View File

@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/of_device.h>
#include "stmpe.h"
static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
@ -52,15 +53,41 @@ static struct stmpe_client_info i2c_ci = {
.write_block = i2c_block_write,
};
static const struct of_device_id stmpe_of_match[] = {
{ .compatible = "st,stmpe610", .data = (void *)STMPE610, },
{ .compatible = "st,stmpe801", .data = (void *)STMPE801, },
{ .compatible = "st,stmpe811", .data = (void *)STMPE811, },
{ .compatible = "st,stmpe1601", .data = (void *)STMPE1601, },
{ .compatible = "st,stmpe1801", .data = (void *)STMPE1801, },
{ .compatible = "st,stmpe2401", .data = (void *)STMPE2401, },
{ .compatible = "st,stmpe2403", .data = (void *)STMPE2403, },
{},
};
MODULE_DEVICE_TABLE(of, stmpe_of_match);
static int
stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
int partnum;
const struct of_device_id *of_id;
i2c_ci.data = (void *)id;
i2c_ci.irq = i2c->irq;
i2c_ci.client = i2c;
i2c_ci.dev = &i2c->dev;
return stmpe_probe(&i2c_ci, id->driver_data);
of_id = of_match_device(stmpe_of_match, &i2c->dev);
if (!of_id) {
/*
* This happens when the I2C ID matches the node name
* but no real compatible string has been given.
*/
dev_info(&i2c->dev, "matching on node name, compatible is preferred\n");
partnum = id->driver_data;
} else
partnum = (int)of_id->data;
return stmpe_probe(&i2c_ci, partnum);
}
static int stmpe_i2c_remove(struct i2c_client *i2c)
@ -89,6 +116,7 @@ static struct i2c_driver stmpe_i2c_driver = {
#ifdef CONFIG_PM
.pm = &stmpe_dev_pm_ops,
#endif
.of_match_table = stmpe_of_match,
},
.probe = stmpe_i2c_probe,
.remove = stmpe_i2c_remove,

View File

@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/mfd/core.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include "stmpe.h"
static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
@ -605,9 +606,18 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
if (blocks & STMPE_BLOCK_GPIO)
mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
else
mask &= ~STMPE1601_SYS_CTRL_ENABLE_GPIO;
if (blocks & STMPE_BLOCK_KEYPAD)
mask |= STMPE1601_SYS_CTRL_ENABLE_KPC;
else
mask &= ~STMPE1601_SYS_CTRL_ENABLE_KPC;
if (blocks & STMPE_BLOCK_PWM)
mask |= STMPE1601_SYS_CTRL_ENABLE_SPWM;
else
mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM;
return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
enable ? mask : 0);
@ -986,9 +996,6 @@ static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np)
int base = 0;
int num_irqs = stmpe->variant->num_irqs;
if (!np)
base = stmpe->irq_base;
stmpe->domain = irq_domain_add_simple(np, num_irqs, base,
&stmpe_irq_ops, stmpe);
if (!stmpe->domain) {
@ -1067,7 +1074,7 @@ static int stmpe_chip_init(struct stmpe *stmpe)
static int stmpe_add_device(struct stmpe *stmpe, const struct mfd_cell *cell)
{
return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
NULL, stmpe->irq_base, stmpe->domain);
NULL, 0, stmpe->domain);
}
static int stmpe_devices_init(struct stmpe *stmpe)
@ -1171,12 +1178,23 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
stmpe->dev = ci->dev;
stmpe->client = ci->client;
stmpe->pdata = pdata;
stmpe->irq_base = pdata->irq_base;
stmpe->ci = ci;
stmpe->partnum = partnum;
stmpe->variant = stmpe_variant_info[partnum];
stmpe->regs = stmpe->variant->regs;
stmpe->num_gpios = stmpe->variant->num_gpios;
stmpe->vcc = devm_regulator_get_optional(ci->dev, "vcc");
if (!IS_ERR(stmpe->vcc)) {
ret = regulator_enable(stmpe->vcc);
if (ret)
dev_warn(ci->dev, "failed to enable VCC supply\n");
}
stmpe->vio = devm_regulator_get_optional(ci->dev, "vio");
if (!IS_ERR(stmpe->vio)) {
ret = regulator_enable(stmpe->vio);
if (ret)
dev_warn(ci->dev, "failed to enable VIO supply\n");
}
dev_set_drvdata(stmpe->dev, stmpe);
if (ci->init)
@ -1243,6 +1261,11 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
int stmpe_remove(struct stmpe *stmpe)
{
if (!IS_ERR(stmpe->vio))
regulator_disable(stmpe->vio);
if (!IS_ERR(stmpe->vcc))
regulator_disable(stmpe->vcc);
mfd_remove_devices(stmpe->dev);
return 0;

View File

@ -192,7 +192,7 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3)
#define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1)
#define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0)
#define STMPE1601_SYS_CTRL_ENABLE_SPWM (1 << 0)
/* The 1601/2403 share the same masks */
#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7)

View File

@ -32,14 +32,6 @@
#define NUM_INT_REG 2
#define TOTAL_NUM_REG 0x18
/* interrupt status registers */
#define TPS65090_INT_STS 0x0
#define TPS65090_INT_STS2 0x1
/* interrupt mask registers */
#define TPS65090_INT_MSK 0x2
#define TPS65090_INT_MSK2 0x3
#define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1
#define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2
#define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3
@ -64,11 +56,16 @@ static struct resource charger_resources[] = {
}
};
static const struct mfd_cell tps65090s[] = {
{
enum tps65090_cells {
PMIC = 0,
CHARGER = 1,
};
static struct mfd_cell tps65090s[] = {
[PMIC] = {
.name = "tps65090-pmic",
},
{
[CHARGER] = {
.name = "tps65090-charger",
.num_resources = ARRAY_SIZE(charger_resources),
.resources = &charger_resources[0],
@ -139,18 +136,27 @@ static struct regmap_irq_chip tps65090_irq_chip = {
.irqs = tps65090_irqs,
.num_irqs = ARRAY_SIZE(tps65090_irqs),
.num_regs = NUM_INT_REG,
.status_base = TPS65090_INT_STS,
.mask_base = TPS65090_INT_MSK,
.status_base = TPS65090_REG_INTR_STS,
.mask_base = TPS65090_REG_INTR_MASK,
.mask_invert = true,
};
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2))
return true;
else
/* Nearly all registers have status bits mixed in, except a few */
switch (reg) {
case TPS65090_REG_INTR_MASK:
case TPS65090_REG_INTR_MASK2:
case TPS65090_REG_CG_CTRL0:
case TPS65090_REG_CG_CTRL1:
case TPS65090_REG_CG_CTRL2:
case TPS65090_REG_CG_CTRL3:
case TPS65090_REG_CG_CTRL4:
case TPS65090_REG_CG_CTRL5:
return false;
}
return true;
}
static const struct regmap_config tps65090_regmap_config = {
.reg_bits = 8,
@ -211,6 +217,9 @@ static int tps65090_i2c_probe(struct i2c_client *client,
"IRQ init failed with err: %d\n", ret);
return ret;
}
} else {
/* Don't tell children they have an IRQ that'll never fire */
tps65090s[CHARGER].num_resources = 0;
}
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,

View File

@ -495,6 +495,10 @@ static void tps6586x_print_version(struct i2c_client *client, int version)
case TPS658623:
name = "TPS658623";
break;
case TPS658640:
case TPS658640v2:
name = "TPS658640";
break;
case TPS658643:
name = "TPS658643";
break;

View File

@ -98,7 +98,11 @@
#define TWL4030_BASEADD_BACKUP 0x0014
#define TWL4030_BASEADD_INT 0x002E
#define TWL4030_BASEADD_PM_MASTER 0x0036
#define TWL4030_BASEADD_PM_RECEIVER 0x005B
#define TWL4030_DCDC_GLOBAL_CFG 0x06
#define SMARTREFLEX_ENABLE BIT(3)
#define TWL4030_BASEADD_RTC 0x001C
#define TWL4030_BASEADD_SECURED_REG 0x0000
@ -1204,6 +1208,11 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
* Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
* SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
*
* Also, always enable SmartReflex bit as that's needed for omaps to
* to do anything over I2C4 for voltage scaling even if SmartReflex
* is disabled. Without the SmartReflex bit omap sys_clkreq idle
* signal will never trigger for retention idle.
*/
if (twl_class_is_4030()) {
u8 temp;
@ -1212,6 +1221,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
TWL4030_DCDC_GLOBAL_CFG);
temp |= SMARTREFLEX_ENABLE;
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
TWL4030_DCDC_GLOBAL_CFG);
}
if (node) {

View File

@ -694,3 +694,10 @@ config MMC_REALTEK_PCI
help
Say Y here to include driver code to support SD/MMC card interface
of Realtek PCI-E card reader
config MMC_REALTEK_USB
tristate "Realtek USB SD/MMC Card Interface Driver"
depends on MFD_RTSX_USB
help
Say Y here to include driver code to support SD/MMC card interface
of Realtek RTS5129/39 series card reader

View File

@ -52,6 +52,7 @@ obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o

File diff suppressed because it is too large Load Diff

View File

@ -28,17 +28,6 @@
#include <linux/mfd/tps65090.h>
#define TPS65090_REG_INTR_STS 0x00
#define TPS65090_REG_INTR_MASK 0x02
#define TPS65090_REG_CG_CTRL0 0x04
#define TPS65090_REG_CG_CTRL1 0x05
#define TPS65090_REG_CG_CTRL2 0x06
#define TPS65090_REG_CG_CTRL3 0x07
#define TPS65090_REG_CG_CTRL4 0x08
#define TPS65090_REG_CG_CTRL5 0x09
#define TPS65090_REG_CG_STATUS1 0x0a
#define TPS65090_REG_CG_STATUS2 0x0b
#define TPS65090_CHARGER_ENABLE BIT(0)
#define TPS65090_VACG BIT(1)
#define TPS65090_NOITERM BIT(5)

View File

@ -266,11 +266,12 @@ config REGULATOR_LP8788
This driver supports LP8788 voltage regulator chip.
config REGULATOR_MAX14577
tristate "Maxim 14577 regulator"
tristate "Maxim 14577/77836 regulator"
depends on MFD_MAX14577
help
This driver controls a Maxim 14577 regulator via I2C bus.
The regulators include safeout LDO and current regulator 'CHARGER'.
This driver controls a Maxim MAX14577/77836 regulator via I2C bus.
The MAX14577 regulators include safeout LDO and charger current
regulator. The MAX77836 has two additional LDOs.
config REGULATOR_MAX1586
tristate "Maxim 1586/1587 voltage regulator"

View File

@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@ -178,6 +179,42 @@ static const struct regulator_init_data arizona_ldo1_default = {
.num_consumer_supplies = 1,
};
static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
struct regulator_config *config)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_ldo1 *ldo1 = config->driver_data;
struct device_node *init_node, *dcvdd_node;
struct regulator_init_data *init_data;
pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true);
init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1");
dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0);
if (init_node) {
config->of_node = init_node;
init_data = of_get_regulator_init_data(arizona->dev, init_node);
if (init_data) {
init_data->consumer_supplies = &ldo1->supply;
init_data->num_consumer_supplies = 1;
if (dcvdd_node && dcvdd_node != init_node)
arizona->external_dcvdd = true;
pdata->ldo1 = init_data;
}
} else if (dcvdd_node) {
arizona->external_dcvdd = true;
}
of_node_put(dcvdd_node);
return 0;
}
static int arizona_ldo1_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@ -186,6 +223,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
struct arizona_ldo1 *ldo1;
int ret;
arizona->external_dcvdd = false;
ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
if (!ldo1)
return -ENOMEM;
@ -216,6 +255,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
config.dev = arizona->dev;
config.driver_data = ldo1;
config.regmap = arizona->regmap;
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_ldo1_of_get_pdata(arizona, &config);
if (ret < 0)
return ret;
}
}
config.ena_gpio = arizona->pdata.ldoena;
if (arizona->pdata.ldo1)
@ -223,6 +271,13 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
else
config.init_data = &ldo1->init_data;
/*
* LDO1 can only be used to supply DCVDD so if it has no
* consumers then DCVDD is supplied externally.
*/
if (config.init_data->num_consumer_supplies == 0)
arizona->external_dcvdd = true;
ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(ldo1->regulator)) {
ret = PTR_ERR(ldo1->regulator);
@ -231,6 +286,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
return ret;
}
of_node_put(config.of_node);
platform_set_drvdata(pdev, ldo1);
return 0;

View File

@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@ -195,6 +196,32 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
.num_consumer_supplies = 1,
};
static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
struct regulator_config *config)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_micsupp *micsupp = config->driver_data;
struct device_node *np;
struct regulator_init_data *init_data;
np = of_get_child_by_name(arizona->dev->of_node, "micvdd");
if (np) {
config->of_node = np;
init_data = of_get_regulator_init_data(arizona->dev, np);
if (init_data) {
init_data->consumer_supplies = &micsupp->supply;
init_data->num_consumer_supplies = 1;
pdata->micvdd = init_data;
}
}
return 0;
}
static int arizona_micsupp_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@ -234,6 +261,14 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
config.driver_data = micsupp;
config.regmap = arizona->regmap;
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_micsupp_of_get_pdata(arizona, &config);
if (ret < 0)
return ret;
}
}
if (arizona->pdata.micvdd)
config.init_data = arizona->pdata.micvdd;
else
@ -253,6 +288,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
return ret;
}
of_node_put(config.of_node);
platform_set_drvdata(pdev, micsupp);
return 0;

View File

@ -1,5 +1,5 @@
/*
* max14577.c - Regulator driver for the Maxim 14577
* max14577.c - Regulator driver for the Maxim 14577/77836
*
* Copyright (C) 2013,2014 Samsung Electronics
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
@ -22,6 +22,42 @@
#include <linux/mfd/max14577-private.h>
#include <linux/regulator/of_regulator.h>
/*
* Valid limits of current for max14577 and max77836 chargers.
* They must correspond to MBCICHWRCL and MBCICHWRCH fields in CHGCTRL4
* register for given chipset.
*/
struct maxim_charger_current {
/* Minimal current, set in CHGCTRL4/MBCICHWRCL, uA */
unsigned int min;
/*
* Minimal current when high setting is active,
* set in CHGCTRL4/MBCICHWRCH, uA
*/
unsigned int high_start;
/* Value of one step in high setting, uA */
unsigned int high_step;
/* Maximum current of high setting, uA */
unsigned int max;
};
/* Table of valid charger currents for different Maxim chipsets */
static const struct maxim_charger_current maxim_charger_currents[] = {
[MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 },
[MAXIM_DEVICE_TYPE_MAX14577] = {
.min = MAX14577_REGULATOR_CURRENT_LIMIT_MIN,
.high_start = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START,
.high_step = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
.max = MAX14577_REGULATOR_CURRENT_LIMIT_MAX,
},
[MAXIM_DEVICE_TYPE_MAX77836] = {
.min = MAX77836_REGULATOR_CURRENT_LIMIT_MIN,
.high_start = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START,
.high_step = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
.max = MAX77836_REGULATOR_CURRENT_LIMIT_MAX,
},
};
static int max14577_reg_is_enabled(struct regulator_dev *rdev)
{
int rid = rdev_get_id(rdev);
@ -47,6 +83,9 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
{
u8 reg_data;
struct regmap *rmap = rdev->regmap;
struct max14577 *max14577 = rdev_get_drvdata(rdev);
const struct maxim_charger_current *limits =
&maxim_charger_currents[max14577->dev_type];
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
@ -54,12 +93,11 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, &reg_data);
if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
return MAX14577_REGULATOR_CURRENT_LIMIT_MIN;
return limits->min;
reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >>
CHGCTRL4_MBCICHWRCH_SHIFT);
return MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
reg_data * MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP;
return limits->high_start + reg_data * limits->high_step;
}
static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
@ -67,33 +105,39 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
{
int i, current_bits = 0xf;
u8 reg_data;
struct max14577 *max14577 = rdev_get_drvdata(rdev);
const struct maxim_charger_current *limits =
&maxim_charger_currents[max14577->dev_type];
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
if (min_uA > MAX14577_REGULATOR_CURRENT_LIMIT_MAX ||
max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_MIN)
if (min_uA > limits->max || max_uA < limits->min)
return -EINVAL;
if (max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START) {
/* Less than 200 mA, so set 90mA (turn only Low Bit off) */
if (max_uA < limits->high_start) {
/*
* Less than high_start,
* so set the minimal current (turn only Low Bit off)
*/
u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT;
return max14577_update_reg(rdev->regmap,
MAX14577_CHG_REG_CHG_CTRL4,
CHGCTRL4_MBCICHWRCL_MASK, reg_data);
}
/* max_uA is in range: <LIMIT_HIGH_START, inifinite>, so search for
* valid current starting from LIMIT_MAX. */
for (i = MAX14577_REGULATOR_CURRENT_LIMIT_MAX;
i >= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START;
i -= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP) {
/*
* max_uA is in range: <high_start, inifinite>, so search for
* valid current starting from maximum current.
*/
for (i = limits->max; i >= limits->high_start; i -= limits->high_step) {
if (i <= max_uA)
break;
current_bits--;
}
BUG_ON(current_bits < 0); /* Cannot happen */
/* Turn Low Bit on (use range 200mA-950 mA) */
/* Turn Low Bit on (use range high_start-max)... */
reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
/* and set proper High Bits */
reg_data |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT;
@ -118,7 +162,7 @@ static struct regulator_ops max14577_charger_ops = {
.set_current_limit = max14577_reg_set_current_limit,
};
static const struct regulator_desc supported_regulators[] = {
static const struct regulator_desc max14577_supported_regulators[] = {
[MAX14577_SAFEOUT] = {
.name = "SAFEOUT",
.id = MAX14577_SAFEOUT,
@ -141,16 +185,88 @@ static const struct regulator_desc supported_regulators[] = {
},
};
static struct regulator_ops max77836_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
/* TODO: add .set_suspend_mode */
};
static const struct regulator_desc max77836_supported_regulators[] = {
[MAX14577_SAFEOUT] = {
.name = "SAFEOUT",
.id = MAX14577_SAFEOUT,
.ops = &max14577_safeout_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.n_voltages = 1,
.min_uV = MAX14577_REGULATOR_SAFEOUT_VOLTAGE,
.enable_reg = MAX14577_REG_CONTROL2,
.enable_mask = CTRL2_SFOUTORD_MASK,
},
[MAX14577_CHARGER] = {
.name = "CHARGER",
.id = MAX14577_CHARGER,
.ops = &max14577_charger_ops,
.type = REGULATOR_CURRENT,
.owner = THIS_MODULE,
.enable_reg = MAX14577_CHG_REG_CHG_CTRL2,
.enable_mask = CHGCTRL2_MBCHOSTEN_MASK,
},
[MAX77836_LDO1] = {
.name = "LDO1",
.id = MAX77836_LDO1,
.ops = &max77836_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
.min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
.uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
.enable_reg = MAX77836_LDO_REG_CNFG1_LDO1,
.enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
.vsel_reg = MAX77836_LDO_REG_CNFG1_LDO1,
.vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
},
[MAX77836_LDO2] = {
.name = "LDO2",
.id = MAX77836_LDO2,
.ops = &max77836_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
.min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
.uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
.enable_reg = MAX77836_LDO_REG_CNFG1_LDO2,
.enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
.vsel_reg = MAX77836_LDO_REG_CNFG1_LDO2,
.vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
},
};
#ifdef CONFIG_OF
static struct of_regulator_match max14577_regulator_matches[] = {
{ .name = "SAFEOUT", },
{ .name = "CHARGER", },
};
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
static struct of_regulator_match max77836_regulator_matches[] = {
{ .name = "SAFEOUT", },
{ .name = "CHARGER", },
{ .name = "LDO1", },
{ .name = "LDO2", },
};
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
enum maxim_device_type dev_type)
{
int ret;
struct device_node *np;
struct of_regulator_match *regulator_matches;
unsigned int regulator_matches_size;
np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!np) {
@ -158,8 +274,19 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
return -EINVAL;
}
ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
MAX14577_REG_MAX);
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
regulator_matches = max77836_regulator_matches;
regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
regulator_matches = max14577_regulator_matches;
regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches);
}
ret = of_regulator_match(&pdev->dev, np, regulator_matches,
regulator_matches_size);
if (ret < 0)
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
else
@ -170,31 +297,74 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
return ret;
}
static inline struct regulator_init_data *match_init_data(int index)
static inline struct regulator_init_data *match_init_data(int index,
enum maxim_device_type dev_type)
{
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
return max77836_regulator_matches[index].init_data;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
return max14577_regulator_matches[index].init_data;
}
}
static inline struct device_node *match_of_node(int index)
static inline struct device_node *match_of_node(int index,
enum maxim_device_type dev_type)
{
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
return max77836_regulator_matches[index].of_node;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
return max14577_regulator_matches[index].of_node;
}
}
#else /* CONFIG_OF */
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
enum maxim_device_type dev_type)
{
return 0;
}
static inline struct regulator_init_data *match_init_data(int index)
static inline struct regulator_init_data *match_init_data(int index,
enum maxim_device_type dev_type)
{
return NULL;
}
static inline struct device_node *match_of_node(int index)
static inline struct device_node *match_of_node(int index,
enum maxim_device_type dev_type)
{
return NULL;
}
#endif /* CONFIG_OF */
/**
* Registers for regulators of max77836 use different I2C slave addresses so
* different regmaps must be used for them.
*
* Returns proper regmap for accessing regulator passed by id.
*/
static struct regmap *max14577_get_regmap(struct max14577 *max14577,
int reg_id)
{
switch (max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
switch (reg_id) {
case MAX77836_SAFEOUT ... MAX77836_CHARGER:
return max14577->regmap;
default:
/* MAX77836_LDO1 ... MAX77836_LDO2 */
return max14577->regmap_pmic;
}
case MAXIM_DEVICE_TYPE_MAX14577:
default:
return max14577->regmap;
}
}
static int max14577_regulator_probe(struct platform_device *pdev)
{
@ -202,15 +372,29 @@ static int max14577_regulator_probe(struct platform_device *pdev)
struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
int i, ret;
struct regulator_config config = {};
const struct regulator_desc *supported_regulators;
unsigned int supported_regulators_size;
enum maxim_device_type dev_type = max14577->dev_type;
ret = max14577_regulator_dt_parse_pdata(pdev);
ret = max14577_regulator_dt_parse_pdata(pdev, dev_type);
if (ret)
return ret;
config.dev = &pdev->dev;
config.regmap = max14577->regmap;
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
supported_regulators = max77836_supported_regulators;
supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
supported_regulators = max14577_supported_regulators;
supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators);
}
for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
config.dev = &pdev->dev;
config.driver_data = max14577;
for (i = 0; i < supported_regulators_size; i++) {
struct regulator_dev *regulator;
/*
* Index of supported_regulators[] is also the id and must
@ -220,17 +404,19 @@ static int max14577_regulator_probe(struct platform_device *pdev)
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].of_node;
} else {
config.init_data = match_init_data(i);
config.of_node = match_of_node(i);
config.init_data = match_init_data(i, dev_type);
config.of_node = match_of_node(i, dev_type);
}
config.regmap = max14577_get_regmap(max14577,
supported_regulators[i].id);
regulator = devm_regulator_register(&pdev->dev,
&supported_regulators[i], &config);
if (IS_ERR(regulator)) {
ret = PTR_ERR(regulator);
dev_err(&pdev->dev,
"Regulator init failed for ID %d with error: %d\n",
i, ret);
"Regulator init failed for %d/%s with error: %d\n",
i, supported_regulators[i].name, ret);
return ret;
}
}
@ -238,20 +424,41 @@ static int max14577_regulator_probe(struct platform_device *pdev)
return ret;
}
static const struct platform_device_id max14577_regulator_id[] = {
{ "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, },
{ "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, },
{ }
};
MODULE_DEVICE_TABLE(platform, max14577_regulator_id);
static struct platform_driver max14577_regulator_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "max14577-regulator",
},
.probe = max14577_regulator_probe,
.id_table = max14577_regulator_id,
};
static int __init max14577_regulator_init(void)
{
/* Check for valid values for charger */
BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
MAX14577_REGULATOR_CURRENT_LIMIT_MAX);
BUILD_BUG_ON(ARRAY_SIZE(supported_regulators) != MAX14577_REG_MAX);
BUILD_BUG_ON(MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START +
MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
MAX77836_REGULATOR_CURRENT_LIMIT_MAX);
/* Valid charger current values must be provided for each chipset */
BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM);
BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM);
BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM);
BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN +
(MAX77836_REGULATOR_LDO_VOLTAGE_STEP *
(MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) !=
MAX77836_REGULATOR_LDO_VOLTAGE_MAX);
return platform_driver_register(&max14577_regulator_driver);
}
@ -264,6 +471,6 @@ static void __exit max14577_regulator_exit(void)
module_exit(max14577_regulator_exit);
MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
MODULE_DESCRIPTION("MAXIM 14577 regulator driver");
MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:max14577-regulator");

View File

@ -68,7 +68,7 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
return rdev_get_dev(rdev)->parent;
}
static struct regulator_ops tps6586x_regulator_ops = {
static struct regulator_ops tps6586x_rw_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@ -79,6 +79,16 @@ static struct regulator_ops tps6586x_regulator_ops = {
.disable = regulator_disable_regmap,
};
static struct regulator_ops tps6586x_ro_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
};
static struct regulator_ops tps6586x_sys_regulator_ops = {
};
@ -106,6 +116,13 @@ static const unsigned int tps6586x_sm2_voltages[] = {
4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000,
};
static int tps658640_sm2_voltages[] = {
2150000, 2200000, 2250000, 2300000, 2350000, 2400000, 2450000, 2500000,
2550000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000, 2900000,
2950000, 3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000,
3350000, 3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000,
};
static const unsigned int tps658643_sm2_voltages[] = {
1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000,
1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000,
@ -120,12 +137,16 @@ static const unsigned int tps6586x_dvm_voltages[] = {
1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
};
#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \
static int tps658640_rtc_voltages[] = {
2500000, 2850000, 3100000, 3300000,
};
#define TPS6586X_REGULATOR(_id, _ops, _pin_name, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
.desc = { \
.supply_name = _pin_name, \
.name = "REG-" #_id, \
.ops = &tps6586x_regulator_ops, \
.ops = &tps6586x_## _ops ## _regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = TPS6586X_ID_##_id, \
.n_voltages = ARRAY_SIZE(vdata##_voltages), \
@ -146,14 +167,21 @@ static const unsigned int tps6586x_dvm_voltages[] = {
#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, 0, 0) \
}
#define TPS6586X_FIXED_LDO(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
TPS6586X_REGULATOR(_id, ro, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, 0, 0) \
}
#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
{ \
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
}
@ -207,6 +235,26 @@ static struct tps6586x_regulator tps658623_regulator[] = {
END, 7),
};
static struct tps6586x_regulator tps658640_regulator[] = {
TPS6586X_LDO(LDO_3, "vinldo23", tps6586x_ldo0, SUPPLYV4, 0, 3,
ENC, 2, END, 2),
TPS6586X_LDO(LDO_5, "REG-SYS", tps6586x_ldo0, SUPPLYV6, 0, 3,
ENE, 6, ENE, 6),
TPS6586X_LDO(LDO_6, "vinldo678", tps6586x_ldo0, SUPPLYV3, 0, 3,
ENC, 4, END, 4),
TPS6586X_LDO(LDO_7, "vinldo678", tps6586x_ldo0, SUPPLYV3, 3, 3,
ENC, 5, END, 5),
TPS6586X_LDO(LDO_8, "vinldo678", tps6586x_ldo0, SUPPLYV2, 5, 3,
ENC, 6, END, 6),
TPS6586X_LDO(LDO_9, "vinldo9", tps6586x_ldo0, SUPPLYV6, 3, 3,
ENE, 7, ENE, 7),
TPS6586X_LDO(SM_2, "vin-sm2", tps658640_sm2, SUPPLYV2, 0, 5,
ENC, 7, END, 7),
TPS6586X_FIXED_LDO(LDO_RTC, "REG-SYS", tps658640_rtc, SUPPLYV4, 3, 2,
V4, 7, V4, 7),
};
static struct tps6586x_regulator tps658643_regulator[] = {
TPS6586X_LDO(SM_2, "vin-sm2", tps658643_sm2, SUPPLYV2, 0, 5, ENC, 7,
END, 7),
@ -295,6 +343,11 @@ static struct tps6586x_regulator *find_regulator_info(int id, int version)
table = tps658623_regulator;
num = ARRAY_SIZE(tps658623_regulator);
break;
case TPS658640:
case TPS658640v2:
table = tps658640_regulator;
num = ARRAY_SIZE(tps658640_regulator);
break;
case TPS658643:
table = tps658643_regulator;
num = ARRAY_SIZE(tps658643_regulator);

View File

@ -468,6 +468,27 @@ struct cpufreq_frequency_table {
* order */
};
bool cpufreq_next_valid(struct cpufreq_frequency_table **pos);
/*
* cpufreq_for_each_entry - iterate over a cpufreq_frequency_table
* @pos: the cpufreq_frequency_table * to use as a loop cursor.
* @table: the cpufreq_frequency_table * to iterate over.
*/
#define cpufreq_for_each_entry(pos, table) \
for (pos = table; pos->frequency != CPUFREQ_TABLE_END; pos++)
/*
* cpufreq_for_each_valid_entry - iterate over a cpufreq_frequency_table
* excluding CPUFREQ_ENTRY_INVALID frequencies.
* @pos: the cpufreq_frequency_table * to use as a loop cursor.
* @table: the cpufreq_frequency_table * to iterate over.
*/
#define cpufreq_for_each_valid_entry(pos, table) \
for (pos = table; cpufreq_next_valid(&pos); pos++)
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table);

View File

@ -124,4 +124,7 @@ int wm5102_patch(struct arizona *arizona);
int wm5110_patch(struct arizona *arizona);
int wm8997_patch(struct arizona *arizona);
extern int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
bool mandatory);
#endif

View File

@ -1,7 +1,7 @@
/*
* max14577-private.h - Common API for the Maxim 14577 internal sub chip
* max14577-private.h - Common API for the Maxim 14577/77836 internal sub chip
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
@ -22,9 +22,19 @@
#include <linux/i2c.h>
#include <linux/regmap.h>
#define MAX14577_REG_INVALID (0xff)
#define I2C_ADDR_PMIC (0x46 >> 1)
#define I2C_ADDR_MUIC (0x4A >> 1)
#define I2C_ADDR_FG (0x6C >> 1)
/* Slave addr = 0x4A: Interrupt */
enum maxim_device_type {
MAXIM_DEVICE_TYPE_UNKNOWN = 0,
MAXIM_DEVICE_TYPE_MAX14577,
MAXIM_DEVICE_TYPE_MAX77836,
MAXIM_DEVICE_TYPE_NUM,
};
/* Slave addr = 0x4A: MUIC and Charger */
enum max14577_reg {
MAX14577_REG_DEVICEID = 0x00,
MAX14577_REG_INT1 = 0x01,
@ -74,20 +84,22 @@ enum max14577_muic_charger_type {
};
/* MAX14577 interrupts */
#define INT1_ADC_MASK (0x1 << 0)
#define INT1_ADCLOW_MASK (0x1 << 1)
#define INT1_ADCERR_MASK (0x1 << 2)
#define MAX14577_INT1_ADC_MASK BIT(0)
#define MAX14577_INT1_ADCLOW_MASK BIT(1)
#define MAX14577_INT1_ADCERR_MASK BIT(2)
#define MAX77836_INT1_ADC1K_MASK BIT(3)
#define INT2_CHGTYP_MASK (0x1 << 0)
#define INT2_CHGDETRUN_MASK (0x1 << 1)
#define INT2_DCDTMR_MASK (0x1 << 2)
#define INT2_DBCHG_MASK (0x1 << 3)
#define INT2_VBVOLT_MASK (0x1 << 4)
#define MAX14577_INT2_CHGTYP_MASK BIT(0)
#define MAX14577_INT2_CHGDETRUN_MASK BIT(1)
#define MAX14577_INT2_DCDTMR_MASK BIT(2)
#define MAX14577_INT2_DBCHG_MASK BIT(3)
#define MAX14577_INT2_VBVOLT_MASK BIT(4)
#define MAX77836_INT2_VIDRM_MASK BIT(5)
#define INT3_EOC_MASK (0x1 << 0)
#define INT3_CGMBC_MASK (0x1 << 1)
#define INT3_OVP_MASK (0x1 << 2)
#define INT3_MBCCHGERR_MASK (0x1 << 3)
#define MAX14577_INT3_EOC_MASK BIT(0)
#define MAX14577_INT3_CGMBC_MASK BIT(1)
#define MAX14577_INT3_OVP_MASK BIT(2)
#define MAX14577_INT3_MBCCHGERR_MASK BIT(3)
/* MAX14577 DEVICE ID register */
#define DEVID_VENDORID_SHIFT 0
@ -99,9 +111,11 @@ enum max14577_muic_charger_type {
#define STATUS1_ADC_SHIFT 0
#define STATUS1_ADCLOW_SHIFT 5
#define STATUS1_ADCERR_SHIFT 6
#define MAX77836_STATUS1_ADC1K_SHIFT 7
#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT)
#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT)
#define STATUS1_ADCLOW_MASK BIT(STATUS1_ADCLOW_SHIFT)
#define STATUS1_ADCERR_MASK BIT(STATUS1_ADCERR_SHIFT)
#define MAX77836_STATUS1_ADC1K_MASK BIT(MAX77836_STATUS1_ADC1K_SHIFT)
/* MAX14577 STATUS2 register */
#define STATUS2_CHGTYP_SHIFT 0
@ -109,11 +123,13 @@ enum max14577_muic_charger_type {
#define STATUS2_DCDTMR_SHIFT 4
#define STATUS2_DBCHG_SHIFT 5
#define STATUS2_VBVOLT_SHIFT 6
#define MAX77836_STATUS2_VIDRM_SHIFT 7
#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT)
#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT)
#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT)
#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT)
#define STATUS2_CHGDETRUN_MASK BIT(STATUS2_CHGDETRUN_SHIFT)
#define STATUS2_DCDTMR_MASK BIT(STATUS2_DCDTMR_SHIFT)
#define STATUS2_DBCHG_MASK BIT(STATUS2_DBCHG_SHIFT)
#define STATUS2_VBVOLT_MASK BIT(STATUS2_VBVOLT_SHIFT)
#define MAX77836_STATUS2_VIDRM_MASK BIT(MAX77836_STATUS2_VIDRM_SHIFT)
/* MAX14577 CONTROL1 register */
#define COMN1SW_SHIFT 0
@ -122,8 +138,8 @@ enum max14577_muic_charger_type {
#define IDBEN_SHIFT 7
#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
#define MICEN_MASK (0x1 << MICEN_SHIFT)
#define IDBEN_MASK (0x1 << IDBEN_SHIFT)
#define MICEN_MASK BIT(MICEN_SHIFT)
#define IDBEN_MASK BIT(IDBEN_SHIFT)
#define CLEAR_IDBEN_MICEN_MASK (COMN1SW_MASK | COMP2SW_MASK)
#define CTRL1_SW_USB ((1 << COMP2SW_SHIFT) \
| (1 << COMN1SW_SHIFT))
@ -143,14 +159,14 @@ enum max14577_muic_charger_type {
#define CTRL2_ACCDET_SHIFT (5)
#define CTRL2_USBCPINT_SHIFT (6)
#define CTRL2_RCPS_SHIFT (7)
#define CTRL2_LOWPWR_MASK (0x1 << CTRL2_LOWPWR_SHIFT)
#define CTRL2_ADCEN_MASK (0x1 << CTRL2_ADCEN_SHIFT)
#define CTRL2_CPEN_MASK (0x1 << CTRL2_CPEN_SHIFT)
#define CTRL2_SFOUTASRT_MASK (0x1 << CTRL2_SFOUTASRT_SHIFT)
#define CTRL2_SFOUTORD_MASK (0x1 << CTRL2_SFOUTORD_SHIFT)
#define CTRL2_ACCDET_MASK (0x1 << CTRL2_ACCDET_SHIFT)
#define CTRL2_USBCPINT_MASK (0x1 << CTRL2_USBCPINT_SHIFT)
#define CTRL2_RCPS_MASK (0x1 << CTR2_RCPS_SHIFT)
#define CTRL2_LOWPWR_MASK BIT(CTRL2_LOWPWR_SHIFT)
#define CTRL2_ADCEN_MASK BIT(CTRL2_ADCEN_SHIFT)
#define CTRL2_CPEN_MASK BIT(CTRL2_CPEN_SHIFT)
#define CTRL2_SFOUTASRT_MASK BIT(CTRL2_SFOUTASRT_SHIFT)
#define CTRL2_SFOUTORD_MASK BIT(CTRL2_SFOUTORD_SHIFT)
#define CTRL2_ACCDET_MASK BIT(CTRL2_ACCDET_SHIFT)
#define CTRL2_USBCPINT_MASK BIT(CTRL2_USBCPINT_SHIFT)
#define CTRL2_RCPS_MASK BIT(CTRL2_RCPS_SHIFT)
#define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \
(0 << CTRL2_LOWPWR_SHIFT))
@ -198,14 +214,14 @@ enum max14577_charger_reg {
#define CDETCTRL1_DBEXIT_SHIFT 5
#define CDETCTRL1_DBIDLE_SHIFT 6
#define CDETCTRL1_CDPDET_SHIFT 7
#define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT)
#define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT)
#define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT)
#define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT)
#define CDETCTRL1_DCHKTM_MASK (0x1 << CDETCTRL1_DCHKTM_SHIFT)
#define CDETCTRL1_DBEXIT_MASK (0x1 << CDETCTRL1_DBEXIT_SHIFT)
#define CDETCTRL1_DBIDLE_MASK (0x1 << CDETCTRL1_DBIDLE_SHIFT)
#define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT)
#define CDETCTRL1_CHGDETEN_MASK BIT(CDETCTRL1_CHGDETEN_SHIFT)
#define CDETCTRL1_CHGTYPMAN_MASK BIT(CDETCTRL1_CHGTYPMAN_SHIFT)
#define CDETCTRL1_DCDEN_MASK BIT(CDETCTRL1_DCDEN_SHIFT)
#define CDETCTRL1_DCD2SCT_MASK BIT(CDETCTRL1_DCD2SCT_SHIFT)
#define CDETCTRL1_DCHKTM_MASK BIT(CDETCTRL1_DCHKTM_SHIFT)
#define CDETCTRL1_DBEXIT_MASK BIT(CDETCTRL1_DBEXIT_SHIFT)
#define CDETCTRL1_DBIDLE_MASK BIT(CDETCTRL1_DBIDLE_SHIFT)
#define CDETCTRL1_CDPDET_MASK BIT(CDETCTRL1_CDPDET_SHIFT)
/* MAX14577 CHGCTRL1 register */
#define CHGCTRL1_TCHW_SHIFT 4
@ -213,9 +229,9 @@ enum max14577_charger_reg {
/* MAX14577 CHGCTRL2 register */
#define CHGCTRL2_MBCHOSTEN_SHIFT 6
#define CHGCTRL2_MBCHOSTEN_MASK (0x1 << CHGCTRL2_MBCHOSTEN_SHIFT)
#define CHGCTRL2_MBCHOSTEN_MASK BIT(CHGCTRL2_MBCHOSTEN_SHIFT)
#define CHGCTRL2_VCHGR_RC_SHIFT 7
#define CHGCTRL2_VCHGR_RC_MASK (0x1 << CHGCTRL2_VCHGR_RC_SHIFT)
#define CHGCTRL2_VCHGR_RC_MASK BIT(CHGCTRL2_VCHGR_RC_SHIFT)
/* MAX14577 CHGCTRL3 register */
#define CHGCTRL3_MBCCVWRC_SHIFT 0
@ -225,7 +241,7 @@ enum max14577_charger_reg {
#define CHGCTRL4_MBCICHWRCH_SHIFT 0
#define CHGCTRL4_MBCICHWRCH_MASK (0xf << CHGCTRL4_MBCICHWRCH_SHIFT)
#define CHGCTRL4_MBCICHWRCL_SHIFT 4
#define CHGCTRL4_MBCICHWRCL_MASK (0x1 << CHGCTRL4_MBCICHWRCL_SHIFT)
#define CHGCTRL4_MBCICHWRCL_MASK BIT(CHGCTRL4_MBCICHWRCL_SHIFT)
/* MAX14577 CHGCTRL5 register */
#define CHGCTRL5_EOCS_SHIFT 0
@ -233,7 +249,7 @@ enum max14577_charger_reg {
/* MAX14577 CHGCTRL6 register */
#define CHGCTRL6_AUTOSTOP_SHIFT 5
#define CHGCTRL6_AUTOSTOP_MASK (0x1 << CHGCTRL6_AUTOSTOP_SHIFT)
#define CHGCTRL6_AUTOSTOP_MASK BIT(CHGCTRL6_AUTOSTOP_SHIFT)
/* MAX14577 CHGCTRL7 register */
#define CHGCTRL7_OTPCGHCVS_SHIFT 0
@ -245,14 +261,111 @@ enum max14577_charger_reg {
#define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP 50000
#define MAX14577_REGULATOR_CURRENT_LIMIT_MAX 950000
/* MAX77836 regulator current limits (as in CHGCTRL4 register), uA */
#define MAX77836_REGULATOR_CURRENT_LIMIT_MIN 45000
#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START 100000
#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP 25000
#define MAX77836_REGULATOR_CURRENT_LIMIT_MAX 475000
/* MAX14577 regulator SFOUT LDO voltage, fixed, uV */
#define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000
/* MAX77836 regulator LDOx voltage, uV */
#define MAX77836_REGULATOR_LDO_VOLTAGE_MIN 800000
#define MAX77836_REGULATOR_LDO_VOLTAGE_MAX 3950000
#define MAX77836_REGULATOR_LDO_VOLTAGE_STEP 50000
#define MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM 64
/* Slave addr = 0x46: PMIC */
enum max77836_pmic_reg {
MAX77836_PMIC_REG_PMIC_ID = 0x20,
MAX77836_PMIC_REG_PMIC_REV = 0x21,
MAX77836_PMIC_REG_INTSRC = 0x22,
MAX77836_PMIC_REG_INTSRC_MASK = 0x23,
MAX77836_PMIC_REG_TOPSYS_INT = 0x24,
MAX77836_PMIC_REG_TOPSYS_INT_MASK = 0x26,
MAX77836_PMIC_REG_TOPSYS_STAT = 0x28,
MAX77836_PMIC_REG_MRSTB_CNTL = 0x2A,
MAX77836_PMIC_REG_LSCNFG = 0x2B,
MAX77836_LDO_REG_CNFG1_LDO1 = 0x51,
MAX77836_LDO_REG_CNFG2_LDO1 = 0x52,
MAX77836_LDO_REG_CNFG1_LDO2 = 0x53,
MAX77836_LDO_REG_CNFG2_LDO2 = 0x54,
MAX77836_LDO_REG_CNFG_LDO_BIAS = 0x55,
MAX77836_COMP_REG_COMP1 = 0x60,
MAX77836_PMIC_REG_END,
};
#define MAX77836_INTSRC_MASK_TOP_INT_SHIFT 1
#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT 3
#define MAX77836_INTSRC_MASK_TOP_INT_MASK BIT(MAX77836_INTSRC_MASK_TOP_INT_SHIFT)
#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK BIT(MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT)
/* MAX77836 PMIC interrupts */
#define MAX77836_TOPSYS_INT_T120C_SHIFT 0
#define MAX77836_TOPSYS_INT_T140C_SHIFT 1
#define MAX77836_TOPSYS_INT_T120C_MASK BIT(MAX77836_TOPSYS_INT_T120C_SHIFT)
#define MAX77836_TOPSYS_INT_T140C_MASK BIT(MAX77836_TOPSYS_INT_T140C_SHIFT)
/* LDO1/LDO2 CONFIG1 register */
#define MAX77836_CNFG1_LDO_PWRMD_SHIFT 6
#define MAX77836_CNFG1_LDO_TV_SHIFT 0
#define MAX77836_CNFG1_LDO_PWRMD_MASK (0x3 << MAX77836_CNFG1_LDO_PWRMD_SHIFT)
#define MAX77836_CNFG1_LDO_TV_MASK (0x3f << MAX77836_CNFG1_LDO_TV_SHIFT)
/* LDO1/LDO2 CONFIG2 register */
#define MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT 7
#define MAX77836_CNFG2_LDO_ALPMEN_SHIFT 6
#define MAX77836_CNFG2_LDO_COMP_SHIFT 4
#define MAX77836_CNFG2_LDO_POK_SHIFT 3
#define MAX77836_CNFG2_LDO_ADE_SHIFT 1
#define MAX77836_CNFG2_LDO_SS_SHIFT 0
#define MAX77836_CNFG2_LDO_OVCLMPEN_MASK BIT(MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT)
#define MAX77836_CNFG2_LDO_ALPMEN_MASK BIT(MAX77836_CNFG2_LDO_ALPMEN_SHIFT)
#define MAX77836_CNFG2_LDO_COMP_MASK (0x3 << MAX77836_CNFG2_LDO_COMP_SHIFT)
#define MAX77836_CNFG2_LDO_POK_MASK BIT(MAX77836_CNFG2_LDO_POK_SHIFT)
#define MAX77836_CNFG2_LDO_ADE_MASK BIT(MAX77836_CNFG2_LDO_ADE_SHIFT)
#define MAX77836_CNFG2_LDO_SS_MASK BIT(MAX77836_CNFG2_LDO_SS_SHIFT)
/* Slave addr = 0x6C: Fuel-Gauge/Battery */
enum max77836_fg_reg {
MAX77836_FG_REG_VCELL_MSB = 0x02,
MAX77836_FG_REG_VCELL_LSB = 0x03,
MAX77836_FG_REG_SOC_MSB = 0x04,
MAX77836_FG_REG_SOC_LSB = 0x05,
MAX77836_FG_REG_MODE_H = 0x06,
MAX77836_FG_REG_MODE_L = 0x07,
MAX77836_FG_REG_VERSION_MSB = 0x08,
MAX77836_FG_REG_VERSION_LSB = 0x09,
MAX77836_FG_REG_HIBRT_H = 0x0A,
MAX77836_FG_REG_HIBRT_L = 0x0B,
MAX77836_FG_REG_CONFIG_H = 0x0C,
MAX77836_FG_REG_CONFIG_L = 0x0D,
MAX77836_FG_REG_VALRT_MIN = 0x14,
MAX77836_FG_REG_VALRT_MAX = 0x15,
MAX77836_FG_REG_CRATE_MSB = 0x16,
MAX77836_FG_REG_CRATE_LSB = 0x17,
MAX77836_FG_REG_VRESET = 0x18,
MAX77836_FG_REG_FGID = 0x19,
MAX77836_FG_REG_STATUS_H = 0x1A,
MAX77836_FG_REG_STATUS_L = 0x1B,
/*
* TODO: TABLE registers
* TODO: CMD register
*/
MAX77836_FG_REG_END,
};
enum max14577_irq {
/* INT1 */
MAX14577_IRQ_INT1_ADC,
MAX14577_IRQ_INT1_ADCLOW,
MAX14577_IRQ_INT1_ADCERR,
MAX77836_IRQ_INT1_ADC1K,
/* INT2 */
MAX14577_IRQ_INT2_CHGTYP,
@ -260,6 +373,7 @@ enum max14577_irq {
MAX14577_IRQ_INT2_DCDTMR,
MAX14577_IRQ_INT2_DBCHG,
MAX14577_IRQ_INT2_VBVOLT,
MAX77836_IRQ_INT2_VIDRM,
/* INT3 */
MAX14577_IRQ_INT3_EOC,
@ -267,21 +381,25 @@ enum max14577_irq {
MAX14577_IRQ_INT3_OVP,
MAX14577_IRQ_INT3_MBCCHGERR,
/* TOPSYS_INT, only MAX77836 */
MAX77836_IRQ_TOPSYS_T140C,
MAX77836_IRQ_TOPSYS_T120C,
MAX14577_IRQ_NUM,
};
struct max14577 {
struct device *dev;
struct i2c_client *i2c; /* Slave addr = 0x4A */
struct i2c_client *i2c_pmic; /* Slave addr = 0x46 */
enum maxim_device_type dev_type;
struct regmap *regmap;
struct regmap *regmap; /* For MUIC and Charger */
struct regmap *regmap_pmic;
struct regmap_irq_chip_data *irq_data;
struct regmap_irq_chip_data *irq_data; /* For MUIC and Charger */
struct regmap_irq_chip_data *irq_data_pmic;
int irq;
/* Device ID */
u8 vendor_id; /* Vendor Identification */
u8 device_id; /* Chip Version */
};
/* MAX14577 shared regmap API function */

View File

@ -1,7 +1,7 @@
/*
* max14577.h - Driver for the Maxim 14577
* max14577.h - Driver for the Maxim 14577/77836
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
@ -20,6 +20,9 @@
* MAX14577 has MUIC, Charger devices.
* The devices share the same I2C bus and interrupt line
* included in this mfd driver.
*
* MAX77836 has additional PMIC and Fuel-Gauge on different I2C slave
* addresses.
*/
#ifndef __MAX14577_H__
@ -32,7 +35,17 @@ enum max14577_regulators {
MAX14577_SAFEOUT = 0,
MAX14577_CHARGER,
MAX14577_REG_MAX,
MAX14577_REGULATOR_NUM,
};
/* MAX77836 regulator IDs */
enum max77836_regulators {
MAX77836_SAFEOUT = 0,
MAX77836_CHARGER,
MAX77836_LDO1,
MAX77836_LDO2,
MAX77836_REGULATOR_NUM,
};
struct max14577_regulator_platform_data {

View File

@ -11,6 +11,7 @@
#include <linux/mutex.h>
struct device;
struct regulator;
enum stmpe_block {
STMPE_BLOCK_GPIO = 1 << 0,
@ -62,6 +63,8 @@ struct stmpe_client_info;
/**
* struct stmpe - STMPE MFD structure
* @vcc: optional VCC regulator
* @vio: optional VIO regulator
* @lock: lock protecting I/O operations
* @irq_lock: IRQ bus lock
* @dev: device, mostly for dev_dbg()
@ -73,13 +76,14 @@ struct stmpe_client_info;
* @regs: list of addresses of registers which are at different addresses on
* different variants. Indexed by one of STMPE_IDX_*.
* @irq: irq number for stmpe
* @irq_base: starting IRQ number for internal IRQs
* @num_gpios: number of gpios, differs for variants
* @ier: cache of IER registers for bus_lock
* @oldier: cache of IER registers for bus_lock
* @pdata: platform data
*/
struct stmpe {
struct regulator *vcc;
struct regulator *vio;
struct mutex lock;
struct mutex irq_lock;
struct device *dev;
@ -91,7 +95,6 @@ struct stmpe {
const u8 *regs;
int irq;
int irq_base;
int num_gpios;
u8 ier[2];
u8 oldier[2];
@ -132,8 +135,6 @@ struct stmpe_keypad_platform_data {
/**
* struct stmpe_gpio_platform_data - STMPE GPIO platform data
* @gpio_base: first gpio number assigned. A maximum of
* %STMPE_NR_GPIOS GPIOs will be allocated.
* @norequest_mask: bitmask specifying which GPIOs should _not_ be
* requestable due to different usage (e.g. touch, keypad)
* STMPE_GPIO_NOREQ_* macros can be used here.
@ -141,7 +142,6 @@ struct stmpe_keypad_platform_data {
* @remove: board specific remove callback
*/
struct stmpe_gpio_platform_data {
int gpio_base;
unsigned norequest_mask;
void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
void (*remove)(struct stmpe *stmpe, unsigned gpio_base);
@ -195,8 +195,6 @@ struct stmpe_ts_platform_data {
* @irq_trigger: IRQ trigger to use for the interrupt to the host
* @autosleep: bool to enable/disable stmpe autosleep
* @autosleep_timeout: inactivity timeout in milliseconds for autosleep
* @irq_base: base IRQ number. %STMPE_NR_IRQS irqs will be used, or
* %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
* @irq_over_gpio: true if gpio is used to get irq
* @irq_gpio: gpio number over which irq will be requested (significant only if
* irq_over_gpio is true)
@ -207,7 +205,6 @@ struct stmpe_ts_platform_data {
struct stmpe_platform_data {
int id;
unsigned int blocks;
int irq_base;
unsigned int irq_trigger;
bool autosleep;
bool irq_over_gpio;
@ -219,10 +216,4 @@ struct stmpe_platform_data {
struct stmpe_ts_platform_data *ts;
};
#define STMPE_NR_INTERNAL_IRQS 9
#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x))
#define STMPE_NR_GPIOS 24
#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS)
#endif

View File

@ -64,6 +64,20 @@ enum {
TPS65090_REGULATOR_MAX,
};
/* Register addresses */
#define TPS65090_REG_INTR_STS 0x00
#define TPS65090_REG_INTR_STS2 0x01
#define TPS65090_REG_INTR_MASK 0x02
#define TPS65090_REG_INTR_MASK2 0x03
#define TPS65090_REG_CG_CTRL0 0x04
#define TPS65090_REG_CG_CTRL1 0x05
#define TPS65090_REG_CG_CTRL2 0x06
#define TPS65090_REG_CG_CTRL3 0x07
#define TPS65090_REG_CG_CTRL4 0x08
#define TPS65090_REG_CG_CTRL5 0x09
#define TPS65090_REG_CG_STATUS1 0x0a
#define TPS65090_REG_CG_STATUS2 0x0b
struct tps65090 {
struct device *dev;
struct regmap *rmap;

View File

@ -17,6 +17,8 @@
#define TPS658621A 0x15
#define TPS658621CD 0x2c
#define TPS658623 0x1b
#define TPS658640 0x01
#define TPS658640v2 0x02
#define TPS658643 0x03
enum {

View File

@ -22,6 +22,7 @@
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/mfd/mc13xxx.h>
#include <linux/slab.h>
#include <sound/core.h>
@ -750,6 +751,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
{
struct mc13783_priv *priv;
struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
struct device_node *np;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@ -760,7 +762,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
priv->adc_ssi_port = pdata->adc_ssi_port;
priv->dac_ssi_port = pdata->dac_ssi_port;
} else {
np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
if (!np)
return -ENOSYS;
ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
if (ret)
return ret;
ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
if (ret)
return ret;
}
dev_set_drvdata(&pdev->dev, priv);