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 objecta613b739b8
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 objectc42ba72ec3
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:
parent
4b660a7f5c
780aaeff96
fdb56c45a2
4bd5e3049b
8a82b408ac
9e9dc7d959
99451dceeb
a613b739b8
c42ba72ec3
commit
28fee3fa0e
54 changed files with 3670 additions and 500 deletions
|
@ -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 = ...
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *
|
||||
*********************************************************************/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
|||
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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -266,7 +266,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
|
|||
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;
|
||||
pos->frequency);
|
||||
pos->frequency = CPUFREQ_ENTRY_INVALID;
|
||||
}
|
||||
|
||||
freq++;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
/*
|
||||
* 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 max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
|
||||
if (irq == muic_irqs[i].virq)
|
||||
irq_type = muic_irqs[i].irq;
|
||||
|
||||
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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
839
drivers/memstick/host/rtsx_usb_ms.c
Normal file
839
drivers/memstick/host/rtsx_usb_ms.c
Normal 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");
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
®_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,
|
||||
®_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");
|
||||
|
|
|
@ -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)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
|
||||
pdata->codec, sizeof(*pdata->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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,17 +136,26 @@ 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 = {
|
||||
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
1455
drivers/mmc/host/rtsx_usb_sdmmc.c
Normal file
1455
drivers/mmc/host/rtsx_usb_sdmmc.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ®_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)
|
||||
{
|
||||
return max14577_regulator_matches[index].init_data;
|
||||
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)
|
||||
{
|
||||
return max14577_regulator_matches[index].of_node;
|
||||
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,
|
||||
.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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#define TPS658621A 0x15
|
||||
#define TPS658621CD 0x2c
|
||||
#define TPS658623 0x1b
|
||||
#define TPS658640 0x01
|
||||
#define TPS658640v2 0x02
|
||||
#define TPS658643 0x03
|
||||
|
||||
enum {
|
||||
|
|
|
@ -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 {
|
||||
return -ENOSYS;
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue