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:
Родитель
4b660a7f5c
780aaeff96
fdb56c45a2
4bd5e3049b
8a82b408ac
9e9dc7d959
99451dceeb
a613b739b8
c42ba72ec3
Коммит
28fee3fa0e
|
@ -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
|
stage. Just pass the values to this function, and the unsigned int
|
||||||
index returns the number of the frequency table entry which contains
|
index returns the number of the frequency table entry which contains
|
||||||
the frequency the CPU shall be set to.
|
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
|
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
|
||||||
|
|
||||||
Sub-nodes:
|
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
|
- leds : Contain the led nodes and initial register values in property
|
||||||
"led-control". Number of register depends of used IC, for MC13783 is 6,
|
"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
|
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)
|
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;
|
unsigned int best = (unsigned int) -1;
|
||||||
struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
|
struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
|
||||||
|
struct cpufreq_frequency_table *pos;
|
||||||
|
|
||||||
rate /= 1000; /* convert to kHz */
|
rate /= 1000; /* convert to kHz */
|
||||||
|
|
||||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_entry(pos, table) {
|
||||||
diff = table[i].frequency - rate;
|
diff = pos->frequency - rate;
|
||||||
if (diff < 0)
|
if (diff < 0)
|
||||||
diff = -diff;
|
diff = -diff;
|
||||||
|
|
||||||
if (diff < best) {
|
if (diff < best) {
|
||||||
best = diff;
|
best = diff;
|
||||||
ret = table[i].frequency;
|
ret = pos->frequency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,15 +46,8 @@
|
||||||
|
|
||||||
static bool is_offset_valid;
|
static bool is_offset_valid;
|
||||||
static u8 smps_offset;
|
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 REG_SMPS_OFFSET 0xE0
|
||||||
#define SMARTREFLEX_ENABLE BIT(3)
|
|
||||||
|
|
||||||
static unsigned long twl4030_vsel_to_uv(const u8 vsel)
|
static unsigned long twl4030_vsel_to_uv(const u8 vsel)
|
||||||
{
|
{
|
||||||
|
@ -251,18 +244,6 @@ int __init omap3_twl_init(void)
|
||||||
if (!cpu_is_omap34xx())
|
if (!cpu_is_omap34xx())
|
||||||
return -ENODEV;
|
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");
|
voltdm = voltdm_lookup("mpu_iva");
|
||||||
omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic);
|
omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic);
|
||||||
|
|
||||||
|
@ -271,44 +252,3 @@ int __init omap3_twl_init(void)
|
||||||
|
|
||||||
return 0;
|
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)
|
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
|
||||||
{
|
{
|
||||||
int i;
|
struct cpufreq_frequency_table *pos;
|
||||||
struct acpi_processor_performance *perf;
|
struct acpi_processor_performance *perf;
|
||||||
|
|
||||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
|
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;
|
perf = data->acpi_data;
|
||||||
|
|
||||||
for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_entry(pos, data->freq_table)
|
||||||
if (msr == perf->states[data->freq_table[i].driver_data].status)
|
if (msr == perf->states[pos->driver_data].status)
|
||||||
return data->freq_table[i].frequency;
|
return pos->frequency;
|
||||||
}
|
|
||||||
return data->freq_table[0].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 */
|
/* get the minimum frequency in the cpufreq_frequency_table */
|
||||||
static inline u32 get_table_min(struct cpufreq_frequency_table *table)
|
static inline u32 get_table_min(struct cpufreq_frequency_table *table)
|
||||||
{
|
{
|
||||||
int i;
|
struct cpufreq_frequency_table *pos;
|
||||||
uint32_t min_freq = ~0;
|
uint32_t min_freq = ~0;
|
||||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
|
cpufreq_for_each_entry(pos, table)
|
||||||
if (table[i].frequency < min_freq)
|
if (pos->frequency < min_freq)
|
||||||
min_freq = table[i].frequency;
|
min_freq = pos->frequency;
|
||||||
return min_freq;
|
return min_freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the maximum frequency in the cpufreq_frequency_table */
|
/* get the maximum frequency in the cpufreq_frequency_table */
|
||||||
static inline u32 get_table_max(struct cpufreq_frequency_table *table)
|
static inline u32 get_table_max(struct cpufreq_frequency_table *table)
|
||||||
{
|
{
|
||||||
int i;
|
struct cpufreq_frequency_table *pos;
|
||||||
uint32_t max_freq = 0;
|
uint32_t max_freq = 0;
|
||||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
|
cpufreq_for_each_entry(pos, table)
|
||||||
if (table[i].frequency > max_freq)
|
if (pos->frequency > max_freq)
|
||||||
max_freq = table[i].frequency;
|
max_freq = pos->frequency;
|
||||||
return max_freq;
|
return max_freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,17 @@ void cpufreq_cpu_put(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
|
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 *
|
* 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)
|
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;
|
struct cpufreq_stats *stat;
|
||||||
unsigned int alloc_size;
|
unsigned int alloc_size;
|
||||||
unsigned int cpu = policy->cpu;
|
unsigned int cpu = policy->cpu;
|
||||||
struct cpufreq_frequency_table *table;
|
struct cpufreq_frequency_table *pos, *table;
|
||||||
|
|
||||||
table = cpufreq_frequency_get_table(cpu);
|
table = cpufreq_frequency_get_table(cpu);
|
||||||
if (unlikely(!table))
|
if (unlikely(!table))
|
||||||
|
@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
||||||
stat->cpu = cpu;
|
stat->cpu = cpu;
|
||||||
per_cpu(cpufreq_stats_table, cpu) = stat;
|
per_cpu(cpufreq_stats_table, cpu) = stat;
|
||||||
|
|
||||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_valid_entry(pos, table)
|
||||||
unsigned int freq = table[i].frequency;
|
|
||||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
|
||||||
continue;
|
|
||||||
count++;
|
count++;
|
||||||
}
|
|
||||||
|
|
||||||
alloc_size = count * sizeof(int) + count * sizeof(u64);
|
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
|
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||||
stat->trans_table = stat->freq_table + count;
|
stat->trans_table = stat->freq_table + count;
|
||||||
#endif
|
#endif
|
||||||
j = 0;
|
i = 0;
|
||||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_valid_entry(pos, table)
|
||||||
unsigned int freq = table[i].frequency;
|
if (freq_table_get_index(stat, pos->frequency) == -1)
|
||||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
stat->freq_table[i++] = pos->frequency;
|
||||||
continue;
|
stat->state_num = i;
|
||||||
if (freq_table_get_index(stat, freq) == -1)
|
|
||||||
stat->freq_table[j++] = freq;
|
|
||||||
}
|
|
||||||
stat->state_num = j;
|
|
||||||
spin_lock(&cpufreq_stats_lock);
|
spin_lock(&cpufreq_stats_lock);
|
||||||
stat->last_time = get_jiffies_64();
|
stat->last_time = get_jiffies_64();
|
||||||
stat->last_index = freq_table_get_index(stat, policy->cur);
|
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)
|
static int dbx500_cpufreq_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int i = 0;
|
struct cpufreq_frequency_table *pos;
|
||||||
|
|
||||||
freq_table = dev_get_platdata(&pdev->dev);
|
freq_table = dev_get_platdata(&pdev->dev);
|
||||||
if (!freq_table) {
|
if (!freq_table) {
|
||||||
|
@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("dbx500-cpufreq: Available frequencies:\n");
|
pr_info("dbx500-cpufreq: Available frequencies:\n");
|
||||||
while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
|
cpufreq_for_each_entry(pos, freq_table)
|
||||||
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
|
pr_info(" %d Mhz\n", pos->frequency / 1000);
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cpufreq_register_driver(&dbx500_cpufreq_driver);
|
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)
|
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||||
unsigned int i;
|
struct cpufreq_frequency_table *pos;
|
||||||
|
|
||||||
/* capability check */
|
/* capability check */
|
||||||
if ((c->x86_vendor != X86_VENDOR_AMD) ||
|
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);
|
max_freq = elanfreq_get_cpu_frequency(0);
|
||||||
|
|
||||||
/* table init */
|
/* table init */
|
||||||
for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
cpufreq_for_each_entry(pos, elanfreq_table)
|
||||||
if (elanfreq_table[i].frequency > max_freq)
|
if (pos->frequency > max_freq)
|
||||||
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
pos->frequency = CPUFREQ_ENTRY_INVALID;
|
||||||
}
|
|
||||||
|
|
||||||
/* cpuinfo and default policy values */
|
/* cpuinfo and default policy values */
|
||||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||||
|
|
|
@ -29,17 +29,16 @@ static unsigned int locking_frequency;
|
||||||
static int exynos_cpufreq_get_index(unsigned int freq)
|
static int exynos_cpufreq_get_index(unsigned int freq)
|
||||||
{
|
{
|
||||||
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
|
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
|
||||||
int index;
|
struct cpufreq_frequency_table *pos;
|
||||||
|
|
||||||
for (index = 0;
|
cpufreq_for_each_entry(pos, freq_table)
|
||||||
freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
|
if (pos->frequency == freq)
|
||||||
if (freq_table[index].frequency == freq)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (freq_table[index].frequency == CPUFREQ_TABLE_END)
|
if (pos->frequency == CPUFREQ_TABLE_END)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return index;
|
return pos - freq_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_cpufreq_scale(unsigned int target_freq)
|
static int exynos_cpufreq_scale(unsigned int target_freq)
|
||||||
|
|
|
@ -114,25 +114,23 @@ static struct cpufreq_freqs freqs;
|
||||||
|
|
||||||
static int init_div_table(void)
|
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;
|
unsigned int tmp, clk_div, ema_div, freq, volt_id;
|
||||||
int i = 0;
|
|
||||||
struct dev_pm_opp *opp;
|
struct dev_pm_opp *opp;
|
||||||
|
|
||||||
rcu_read_lock();
|
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,
|
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
|
||||||
freq_tbl[i].frequency * 1000, true);
|
pos->frequency * 1000, true);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
dev_err(dvfs_info->dev,
|
dev_err(dvfs_info->dev,
|
||||||
"failed to find valid OPP for %u KHZ\n",
|
"failed to find valid OPP for %u KHZ\n",
|
||||||
freq_tbl[i].frequency);
|
pos->frequency);
|
||||||
return PTR_ERR(opp);
|
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)
|
clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
|
||||||
<< P0_7_CPUCLKDEV_SHIFT;
|
<< P0_7_CPUCLKDEV_SHIFT;
|
||||||
clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
|
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)
|
tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
|
||||||
| ((freq / FREQ_UNIT) << P0_7_FREQ_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();
|
rcu_read_unlock();
|
||||||
|
@ -166,8 +165,9 @@ static int init_div_table(void)
|
||||||
|
|
||||||
static void exynos_enable_dvfs(unsigned int cur_frequency)
|
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 *freq_table = dvfs_info->freq_table;
|
||||||
|
struct cpufreq_frequency_table *pos;
|
||||||
/* Disable DVFS */
|
/* Disable DVFS */
|
||||||
__raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
|
__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);
|
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
|
||||||
|
|
||||||
/* Set initial performance index */
|
/* Set initial performance index */
|
||||||
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
|
cpufreq_for_each_entry(pos, freq_table)
|
||||||
if (freq_table[i].frequency == cur_frequency)
|
if (pos->frequency == cur_frequency)
|
||||||
break;
|
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");
|
dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
|
||||||
/* Assign the highest frequency */
|
/* Assign the highest frequency */
|
||||||
i = 0;
|
pos = freq_table;
|
||||||
cur_frequency = freq_table[i].frequency;
|
cur_frequency = pos->frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
|
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++) {
|
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
|
||||||
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
|
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
|
||||||
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
|
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);
|
__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,
|
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
|
||||||
struct cpufreq_frequency_table *table)
|
struct cpufreq_frequency_table *table)
|
||||||
{
|
{
|
||||||
|
struct cpufreq_frequency_table *pos;
|
||||||
unsigned int min_freq = ~0;
|
unsigned int min_freq = ~0;
|
||||||
unsigned int max_freq = 0;
|
unsigned int max_freq = 0;
|
||||||
unsigned int i;
|
unsigned int freq;
|
||||||
|
|
||||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
cpufreq_for_each_valid_entry(pos, table) {
|
||||||
unsigned int freq = table[i].frequency;
|
freq = pos->frequency;
|
||||||
if (freq == CPUFREQ_ENTRY_INVALID) {
|
|
||||||
pr_debug("table entry %u is invalid, skipping\n", i);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!cpufreq_boost_enabled()
|
if (!cpufreq_boost_enabled()
|
||||||
&& (table[i].flags & CPUFREQ_BOOST_FREQ))
|
&& (pos->flags & CPUFREQ_BOOST_FREQ))
|
||||||
continue;
|
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)
|
if (freq < min_freq)
|
||||||
min_freq = freq;
|
min_freq = freq;
|
||||||
if (freq > max_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,
|
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
|
||||||
struct cpufreq_frequency_table *table)
|
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;
|
bool found = false;
|
||||||
|
|
||||||
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
|
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);
|
cpufreq_verify_within_cpu_limits(policy);
|
||||||
|
|
||||||
for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_valid_entry(pos, table) {
|
||||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
freq = pos->frequency;
|
||||||
continue;
|
|
||||||
if ((freq >= policy->min) && (freq <= policy->max)) {
|
if ((freq >= policy->min) && (freq <= policy->max)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -118,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
||||||
.driver_data = ~0,
|
.driver_data = ~0,
|
||||||
.frequency = 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",
|
pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
|
||||||
target_freq, relation, policy->cpu);
|
target_freq, relation, policy->cpu);
|
||||||
|
@ -132,10 +131,10 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
cpufreq_for_each_valid_entry(pos, table) {
|
||||||
unsigned int freq = table[i].frequency;
|
freq = pos->frequency;
|
||||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
|
||||||
continue;
|
i = pos - table;
|
||||||
if ((freq < policy->min) || (freq > policy->max))
|
if ((freq < policy->min) || (freq > policy->max))
|
||||||
continue;
|
continue;
|
||||||
switch (relation) {
|
switch (relation) {
|
||||||
|
@ -184,8 +183,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
|
||||||
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
||||||
unsigned int freq)
|
unsigned int freq)
|
||||||
{
|
{
|
||||||
struct cpufreq_frequency_table *table;
|
struct cpufreq_frequency_table *pos, *table;
|
||||||
int i;
|
|
||||||
|
|
||||||
table = cpufreq_frequency_get_table(policy->cpu);
|
table = cpufreq_frequency_get_table(policy->cpu);
|
||||||
if (unlikely(!table)) {
|
if (unlikely(!table)) {
|
||||||
|
@ -193,10 +191,9 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_valid_entry(pos, table)
|
||||||
if (table[i].frequency == freq)
|
if (pos->frequency == freq)
|
||||||
return i;
|
return pos - table;
|
||||||
}
|
|
||||||
|
|
||||||
return -EINVAL;
|
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,
|
static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
|
||||||
bool show_boost)
|
bool show_boost)
|
||||||
{
|
{
|
||||||
unsigned int i = 0;
|
|
||||||
ssize_t count = 0;
|
ssize_t count = 0;
|
||||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
struct cpufreq_frequency_table *pos, *table = policy->freq_table;
|
||||||
|
|
||||||
if (!table)
|
if (!table)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
cpufreq_for_each_valid_entry(pos, table) {
|
||||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
|
||||||
continue;
|
|
||||||
/*
|
/*
|
||||||
* show_boost = true and driver_data = BOOST freq
|
* show_boost = true and driver_data = BOOST freq
|
||||||
* display BOOST freqs
|
* 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
|
* show_boost = false and driver_data != BOOST freq
|
||||||
* display NON BOOST freqs
|
* display NON BOOST freqs
|
||||||
*/
|
*/
|
||||||
if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ))
|
if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
count += sprintf(&buf[count], "%d ", table[i].frequency);
|
count += sprintf(&buf[count], "%d ", pos->frequency);
|
||||||
}
|
}
|
||||||
count += sprintf(&buf[count], "\n");
|
count += sprintf(&buf[count], "\n");
|
||||||
|
|
||||||
|
|
|
@ -530,6 +530,7 @@ static int longhaul_get_ranges(void)
|
||||||
|
|
||||||
static void longhaul_setup_voltagescaling(void)
|
static void longhaul_setup_voltagescaling(void)
|
||||||
{
|
{
|
||||||
|
struct cpufreq_frequency_table *freq_pos;
|
||||||
union msr_longhaul longhaul;
|
union msr_longhaul longhaul;
|
||||||
struct mV_pos minvid, maxvid, vid;
|
struct mV_pos minvid, maxvid, vid;
|
||||||
unsigned int j, speed, pos, kHz_step, numvscales;
|
unsigned int j, speed, pos, kHz_step, numvscales;
|
||||||
|
@ -608,18 +609,16 @@ static void longhaul_setup_voltagescaling(void)
|
||||||
/* Calculate kHz for one voltage step */
|
/* Calculate kHz for one voltage step */
|
||||||
kHz_step = (highest_speed - min_vid_speed) / numvscales;
|
kHz_step = (highest_speed - min_vid_speed) / numvscales;
|
||||||
|
|
||||||
j = 0;
|
cpufreq_for_each_entry(freq_pos, longhaul_table) {
|
||||||
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
|
speed = freq_pos->frequency;
|
||||||
speed = longhaul_table[j].frequency;
|
|
||||||
if (speed > min_vid_speed)
|
if (speed > min_vid_speed)
|
||||||
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
|
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
|
||||||
else
|
else
|
||||||
pos = minvid.pos;
|
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]];
|
vid = vrm_mV_table[mV_vrm_table[pos]];
|
||||||
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
|
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
|
||||||
speed, j, vid.mV);
|
speed, (int)(freq_pos - longhaul_table), vid.mV);
|
||||||
j++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
can_scale_voltage = 1;
|
can_scale_voltage = 1;
|
||||||
|
|
|
@ -136,9 +136,10 @@ void restore_astate(int cpu)
|
||||||
|
|
||||||
static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
|
struct cpufreq_frequency_table *pos;
|
||||||
const u32 *max_freqp;
|
const u32 *max_freqp;
|
||||||
u32 max_freq;
|
u32 max_freq;
|
||||||
int i, cur_astate;
|
int cur_astate;
|
||||||
struct resource res;
|
struct resource res;
|
||||||
struct device_node *cpu, *dn;
|
struct device_node *cpu, *dn;
|
||||||
int err = -ENODEV;
|
int err = -ENODEV;
|
||||||
|
@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
pr_debug("initializing frequency table\n");
|
pr_debug("initializing frequency table\n");
|
||||||
|
|
||||||
/* initialize frequency table */
|
/* initialize frequency table */
|
||||||
for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_entry(pos, pas_freqs) {
|
||||||
pas_freqs[i].frequency =
|
pos->frequency = get_astate_freq(pos->driver_data) * 100000;
|
||||||
get_astate_freq(pas_freqs[i].driver_data) * 100000;
|
pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency);
|
||||||
pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_astate = get_cur_astate(policy->cpu);
|
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)
|
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
|
struct cpufreq_frequency_table *pos;
|
||||||
unsigned int i, f;
|
unsigned int i, f;
|
||||||
unsigned khz;
|
unsigned khz;
|
||||||
|
|
||||||
|
@ -168,12 +169,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (param_max_multiplier) {
|
if (param_max_multiplier) {
|
||||||
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
|
cpufreq_for_each_entry(pos, clock_ratio)
|
||||||
if (clock_ratio[i].driver_data == param_max_multiplier) {
|
if (pos->driver_data == param_max_multiplier) {
|
||||||
max_multiplier = param_max_multiplier;
|
max_multiplier = param_max_multiplier;
|
||||||
goto have_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");
|
printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -201,12 +201,12 @@ have_busfreq:
|
||||||
param_busfreq = busfreq * 10;
|
param_busfreq = busfreq * 10;
|
||||||
|
|
||||||
/* table init */
|
/* table init */
|
||||||
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
|
cpufreq_for_each_entry(pos, clock_ratio) {
|
||||||
f = clock_ratio[i].driver_data;
|
f = pos->driver_data;
|
||||||
if (f > max_multiplier)
|
if (f > max_multiplier)
|
||||||
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
|
pos->frequency = CPUFREQ_ENTRY_INVALID;
|
||||||
else
|
else
|
||||||
clock_ratio[i].frequency = busfreq * f;
|
pos->frequency = busfreq * f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cpuinfo and default policy values */
|
/* 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)
|
static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
|
struct cpufreq_frequency_table *pos;
|
||||||
const u32 *max_freqp;
|
const u32 *max_freqp;
|
||||||
u32 max_freq;
|
u32 max_freq;
|
||||||
int i, cur_pmode;
|
int cur_pmode;
|
||||||
struct device_node *cpu;
|
struct device_node *cpu;
|
||||||
|
|
||||||
cpu = of_get_cpu_node(policy->cpu, NULL);
|
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");
|
pr_debug("initializing frequency table\n");
|
||||||
|
|
||||||
/* initialize frequency table */
|
/* initialize frequency table */
|
||||||
for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
|
cpufreq_for_each_entry(pos, cbe_freqs) {
|
||||||
cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
|
pos->frequency = max_freq / pos->driver_data;
|
||||||
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
|
pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if DEBUG is enabled set_pmode() measures the latency
|
/* if DEBUG is enabled set_pmode() measures the latency
|
||||||
|
|
|
@ -266,7 +266,7 @@ out:
|
||||||
static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
|
static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
|
||||||
{
|
{
|
||||||
int count, v, i, found;
|
int count, v, i, found;
|
||||||
struct cpufreq_frequency_table *freq;
|
struct cpufreq_frequency_table *pos;
|
||||||
struct s3c2416_dvfs *dvfs;
|
struct s3c2416_dvfs *dvfs;
|
||||||
|
|
||||||
count = regulator_count_voltages(s3c_freq->vddarm);
|
count = regulator_count_voltages(s3c_freq->vddarm);
|
||||||
|
@ -275,12 +275,11 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
freq = s3c_freq->freq_table;
|
if (!count)
|
||||||
while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
|
goto out;
|
||||||
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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;
|
found = 0;
|
||||||
|
|
||||||
/* Check only the min-voltage, more is always ok on S3C2416 */
|
/* 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) {
|
if (!found) {
|
||||||
pr_debug("cpufreq: %dkHz unsupported by regulator\n",
|
pr_debug("cpufreq: %dkHz unsupported by regulator\n",
|
||||||
freq->frequency);
|
pos->frequency);
|
||||||
freq->frequency = CPUFREQ_ENTRY_INVALID;
|
pos->frequency = CPUFREQ_ENTRY_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
freq++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
/* Guessed */
|
/* Guessed */
|
||||||
s3c_freq->regulator_latency = 1 * 1000 * 1000;
|
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)
|
static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
|
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
|
||||||
struct cpufreq_frequency_table *freq;
|
struct cpufreq_frequency_table *pos;
|
||||||
struct clk *msysclk;
|
struct clk *msysclk;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -427,31 +425,27 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||||
s3c_freq->regulator_latency = 0;
|
s3c_freq->regulator_latency = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
freq = s3c_freq->freq_table;
|
cpufreq_for_each_entry(pos, s3c_freq->freq_table) {
|
||||||
while (freq->frequency != CPUFREQ_TABLE_END) {
|
|
||||||
/* special handling for dvs mode */
|
/* special handling for dvs mode */
|
||||||
if (freq->driver_data == 0) {
|
if (pos->driver_data == 0) {
|
||||||
if (!s3c_freq->hclk) {
|
if (!s3c_freq->hclk) {
|
||||||
pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
|
pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
|
||||||
freq->frequency);
|
pos->frequency);
|
||||||
freq->frequency = CPUFREQ_ENTRY_INVALID;
|
pos->frequency = CPUFREQ_ENTRY_INVALID;
|
||||||
} else {
|
} else {
|
||||||
freq++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for frequencies we can generate */
|
/* Check for frequencies we can generate */
|
||||||
rate = clk_round_rate(s3c_freq->armdiv,
|
rate = clk_round_rate(s3c_freq->armdiv,
|
||||||
freq->frequency * 1000);
|
pos->frequency * 1000);
|
||||||
rate /= 1000;
|
rate /= 1000;
|
||||||
if (rate != freq->frequency) {
|
if (rate != pos->frequency) {
|
||||||
pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
|
pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
|
||||||
freq->frequency, rate);
|
pos->frequency, rate);
|
||||||
freq->frequency = CPUFREQ_ENTRY_INVALID;
|
pos->frequency = CPUFREQ_ENTRY_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
freq++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Datasheet says PLL stabalisation time must be at least 300us,
|
/* 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");
|
pr_err("Unable to check supported voltages\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
freq = s3c64xx_freq_table;
|
if (!count)
|
||||||
while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
|
goto out;
|
||||||
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
cpufreq_for_each_valid_entry(freq, s3c64xx_freq_table) {
|
||||||
dvfs = &s3c64xx_dvfs_table[freq->driver_data];
|
dvfs = &s3c64xx_dvfs_table[freq->driver_data];
|
||||||
found = 0;
|
found = 0;
|
||||||
|
|
||||||
|
@ -137,10 +136,9 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
|
||||||
freq->frequency);
|
freq->frequency);
|
||||||
freq->frequency = CPUFREQ_ENTRY_INVALID;
|
freq->frequency = CPUFREQ_ENTRY_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
freq++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
/* Guess based on having to do an I2C/SPI write; in future we
|
/* Guess based on having to do an I2C/SPI write; in future we
|
||||||
* will be able to query the regulator performance here. */
|
* will be able to query the regulator performance here. */
|
||||||
regulator_latency = 1 * 1000 * 1000;
|
regulator_latency = 1 * 1000 * 1000;
|
||||||
|
@ -179,8 +177,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
freq = s3c64xx_freq_table;
|
cpufreq_for_each_entry(freq, s3c64xx_freq_table) {
|
||||||
while (freq->frequency != CPUFREQ_TABLE_END) {
|
|
||||||
unsigned long r;
|
unsigned long r;
|
||||||
|
|
||||||
/* Check for frequencies we can generate */
|
/* 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. */
|
* frequency is the maximum we can support. */
|
||||||
if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000)
|
if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000)
|
||||||
freq->frequency = CPUFREQ_ENTRY_INVALID;
|
freq->frequency = CPUFREQ_ENTRY_INVALID;
|
||||||
|
|
||||||
freq++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Datasheet says PLL stabalisation time (if we were to use
|
/* 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.
|
Say Y here to enable extcon device driver based on ADC values.
|
||||||
|
|
||||||
config EXTCON_MAX14577
|
config EXTCON_MAX14577
|
||||||
tristate "MAX14577 EXTCON Support"
|
tristate "MAX14577/77836 EXTCON Support"
|
||||||
depends on MFD_MAX14577
|
depends on MFD_MAX14577
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the MUIC device of
|
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.
|
detector and switch.
|
||||||
|
|
||||||
config EXTCON_MAX77693
|
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>
|
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||||
|
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* 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/mfd/max14577-private.h>
|
||||||
#include <linux/extcon.h>
|
#include <linux/extcon.h>
|
||||||
|
|
||||||
#define DEV_NAME "max14577-muic"
|
|
||||||
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
|
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
|
||||||
|
|
||||||
enum max14577_muic_adc_debounce_time {
|
enum max14577_muic_adc_debounce_time {
|
||||||
|
@ -40,6 +40,42 @@ enum max14577_muic_status {
|
||||||
MAX14577_MUIC_STATUS_END,
|
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 max14577_muic_info {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct max14577 *max14577;
|
struct max14577 *max14577;
|
||||||
|
@ -48,6 +84,8 @@ struct max14577_muic_info {
|
||||||
int prev_chg_type;
|
int prev_chg_type;
|
||||||
u8 status[MAX14577_MUIC_STATUS_END];
|
u8 status[MAX14577_MUIC_STATUS_END];
|
||||||
|
|
||||||
|
struct max14577_muic_irq *muic_irqs;
|
||||||
|
unsigned int muic_irqs_num;
|
||||||
bool irq_adc;
|
bool irq_adc;
|
||||||
bool irq_chg;
|
bool irq_chg;
|
||||||
struct work_struct irq_work;
|
struct work_struct irq_work;
|
||||||
|
@ -74,29 +112,6 @@ enum max14577_muic_cable_group {
|
||||||
MAX14577_CABLE_GROUP_CHG,
|
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 */
|
/* Define supported accessory type */
|
||||||
enum max14577_muic_acc_type {
|
enum max14577_muic_acc_type {
|
||||||
MAX14577_MUIC_ADC_GROUND = 0x0,
|
MAX14577_MUIC_ADC_GROUND = 0x0,
|
||||||
|
@ -528,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work)
|
||||||
return;
|
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) {
|
switch (irq_type) {
|
||||||
case MAX14577_IRQ_INT1_ADC:
|
case MAX14577_IRQ_INT1_ADC:
|
||||||
case MAX14577_IRQ_INT1_ADCLOW:
|
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
|
/* Handle all of accessory except for
|
||||||
type of charger accessory */
|
type of charger accessory */
|
||||||
info->irq_adc = true;
|
info->irq_adc = true;
|
||||||
break;
|
return 1;
|
||||||
case MAX14577_IRQ_INT2_CHGTYP:
|
case MAX14577_IRQ_INT2_CHGTYP:
|
||||||
case MAX14577_IRQ_INT2_CHGDETRUN:
|
case MAX14577_IRQ_INT2_CHGDETRUN:
|
||||||
case MAX14577_IRQ_INT2_DCDTMR:
|
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:
|
case MAX14577_IRQ_INT2_VBVOLT:
|
||||||
/* Handle charger accessory */
|
/* Handle charger accessory */
|
||||||
info->irq_chg = true;
|
info->irq_chg = true;
|
||||||
break;
|
return 1;
|
||||||
default:
|
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",
|
dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
|
||||||
irq_type);
|
irq_type);
|
||||||
return IRQ_HANDLED;
|
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);
|
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 */
|
/* Support irq domain for max14577 MUIC device */
|
||||||
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
|
for (i = 0; i < info->muic_irqs_num; i++) {
|
||||||
struct max14577_muic_irq *muic_irq = &muic_irqs[i];
|
struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
|
||||||
unsigned int virq = 0;
|
unsigned int virq = 0;
|
||||||
|
|
||||||
virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
|
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");
|
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
info->edev->name = DEV_NAME;
|
|
||||||
|
info->edev->name = dev_name(&pdev->dev);
|
||||||
info->edev->supported_cable = max14577_extcon_cable;
|
info->edev->supported_cable = max14577_extcon_cable;
|
||||||
ret = extcon_dev_register(info->edev);
|
ret = extcon_dev_register(info->edev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -735,18 +807,26 @@ static int max14577_muic_remove(struct platform_device *pdev)
|
||||||
return 0;
|
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 = {
|
static struct platform_driver max14577_muic_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DEV_NAME,
|
.name = "max14577-muic",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
},
|
},
|
||||||
.probe = max14577_muic_probe,
|
.probe = max14577_muic_probe,
|
||||||
.remove = max14577_muic_remove,
|
.remove = max14577_muic_remove,
|
||||||
|
.id_table = max14577_muic_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(max14577_muic_driver);
|
module_platform_driver(max14577_muic_driver);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
|
MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");
|
||||||
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
|
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:extcon-max14577");
|
MODULE_ALIAS("platform:extcon-max14577");
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
enum { REG_RE, REG_FE, REG_IE };
|
enum { REG_RE, REG_FE, REG_IE };
|
||||||
|
|
||||||
#define CACHE_NR_REGS 3
|
#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 stmpe_gpio {
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
|
@ -31,8 +32,6 @@ struct stmpe_gpio {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct mutex irq_lock;
|
struct mutex irq_lock;
|
||||||
struct irq_domain *domain;
|
struct irq_domain *domain;
|
||||||
|
|
||||||
int irq_base;
|
|
||||||
unsigned norequest_mask;
|
unsigned norequest_mask;
|
||||||
|
|
||||||
/* Caches of interrupt control registers for bus_lock */
|
/* 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,
|
static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
|
||||||
struct device_node *np)
|
struct device_node *np)
|
||||||
{
|
{
|
||||||
int base = 0;
|
|
||||||
|
|
||||||
if (!np)
|
|
||||||
base = stmpe_gpio->irq_base;
|
|
||||||
|
|
||||||
stmpe_gpio->domain = irq_domain_add_simple(np,
|
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);
|
&stmpe_gpio_irq_simple_ops, stmpe_gpio);
|
||||||
if (!stmpe_gpio->domain) {
|
if (!stmpe_gpio->domain) {
|
||||||
dev_err(stmpe_gpio->dev, "failed to create irqdomain\n");
|
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
|
#ifdef CONFIG_OF
|
||||||
stmpe_gpio->chip.of_node = np;
|
stmpe_gpio->chip.of_node = np;
|
||||||
#endif
|
#endif
|
||||||
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
|
stmpe_gpio->chip.base = -1;
|
||||||
|
|
||||||
if (pdata)
|
if (pdata)
|
||||||
stmpe_gpio->norequest_mask = pdata->norequest_mask;
|
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",
|
of_property_read_u32(np, "st,norequest-mask",
|
||||||
&stmpe_gpio->norequest_mask);
|
&stmpe_gpio->norequest_mask);
|
||||||
|
|
||||||
if (irq >= 0)
|
if (irq < 0)
|
||||||
stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
|
|
||||||
else
|
|
||||||
dev_info(&pdev->dev,
|
dev_info(&pdev->dev,
|
||||||
"device configured in no-irq mode; "
|
"device configured in no-irq mode; "
|
||||||
"irqs are not available\n");
|
"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
|
To compile this driver as a module, choose M here: the module will
|
||||||
be called rtsx_pci_ms.
|
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_JMICRON_38X) += jmb38x_ms.o
|
||||||
obj-$(CONFIG_MEMSTICK_R592) += r592.o
|
obj-$(CONFIG_MEMSTICK_R592) += r592.o
|
||||||
obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o
|
obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o
|
||||||
|
obj-$(CONFIG_MEMSTICK_REALTEK_USB) += rtsx_usb_ms.o
|
||||||
|
|
|
@ -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.
|
battery-charger under the corresponding menus.
|
||||||
|
|
||||||
config MFD_MAX14577
|
config MFD_MAX14577
|
||||||
bool "Maxim Semiconductor MAX14577 MUIC + Charger Support"
|
bool "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support"
|
||||||
depends on I2C=y
|
depends on I2C=y
|
||||||
select MFD_CORE
|
select MFD_CORE
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
select REGMAP_IRQ
|
select REGMAP_IRQ
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
help
|
help
|
||||||
Say yes here to add support for Maxim Semiconductor MAX14577.
|
Say yes here to add support for Maxim Semiconductor MAX14577 and
|
||||||
This is a Micro-USB IC with Charger controls on chip.
|
MAX77836 Micro-USB ICs with battery charger.
|
||||||
This driver provides common support for accessing the device;
|
This driver provides common support for accessing the device;
|
||||||
additional drivers must be enabled in order to use the functionality
|
additional drivers must be enabled in order to use the functionality
|
||||||
of the device.
|
of the device.
|
||||||
|
@ -675,6 +675,7 @@ config MFD_DB8500_PRCMU
|
||||||
config MFD_STMPE
|
config MFD_STMPE
|
||||||
bool "STMicroelectronics STMPE"
|
bool "STMicroelectronics STMPE"
|
||||||
depends on (I2C=y || SPI_MASTER=y)
|
depends on (I2C=y || SPI_MASTER=y)
|
||||||
|
depends on OF
|
||||||
select MFD_CORE
|
select MFD_CORE
|
||||||
help
|
help
|
||||||
Support for the STMPE family of I/O Expanders from
|
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);
|
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)
|
static int arizona_of_get_core_pdata(struct arizona *arizona)
|
||||||
{
|
{
|
||||||
|
struct arizona_pdata *pdata = &arizona->pdata;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
|
pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
|
||||||
"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;
|
|
||||||
|
|
||||||
ret = of_property_read_u32_array(arizona->dev->of_node,
|
ret = of_property_read_u32_array(arizona->dev->of_node,
|
||||||
"wlf,gpio-defaults",
|
"wlf,gpio-defaults",
|
||||||
|
@ -652,6 +664,9 @@ int arizona_dev_init(struct arizona *arizona)
|
||||||
return -EINVAL;
|
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,
|
ret = mfd_add_devices(arizona->dev, -1, early_devs,
|
||||||
ARRAY_SIZE(early_devs), NULL, 0, NULL);
|
ARRAY_SIZE(early_devs), NULL, 0, NULL);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
|
@ -851,14 +866,6 @@ int arizona_dev_init(struct arizona *arizona)
|
||||||
arizona->pdata.gpio_defaults[i]);
|
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_set_autosuspend_delay(arizona->dev, 100);
|
||||||
pm_runtime_use_autosuspend(arizona->dev);
|
pm_runtime_use_autosuspend(arizona->dev);
|
||||||
pm_runtime_enable(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)
|
static long round_armss_rate(unsigned long rate)
|
||||||
{
|
{
|
||||||
|
struct cpufreq_frequency_table *pos;
|
||||||
long freq = 0;
|
long freq = 0;
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/* cpufreq table frequencies is in KHz. */
|
/* cpufreq table frequencies is in KHz. */
|
||||||
rate = rate / 1000;
|
rate = rate / 1000;
|
||||||
|
|
||||||
/* Find the corresponding arm opp from the cpufreq table. */
|
/* Find the corresponding arm opp from the cpufreq table. */
|
||||||
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
|
cpufreq_for_each_entry(pos, db8500_cpufreq_table) {
|
||||||
freq = db8500_cpufreq_table[i].frequency;
|
freq = pos->frequency;
|
||||||
if (freq == rate)
|
if (freq == rate)
|
||||||
break;
|
break;
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the last valid value, even if a match was not found. */
|
/* 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)
|
static int set_armss_rate(unsigned long rate)
|
||||||
{
|
{
|
||||||
int i = 0;
|
struct cpufreq_frequency_table *pos;
|
||||||
|
|
||||||
/* cpufreq table frequencies is in KHz. */
|
/* cpufreq table frequencies is in KHz. */
|
||||||
rate = rate / 1000;
|
rate = rate / 1000;
|
||||||
|
|
||||||
/* Find the corresponding arm opp from the cpufreq table. */
|
/* Find the corresponding arm opp from the cpufreq table. */
|
||||||
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
|
cpufreq_for_each_entry(pos, db8500_cpufreq_table)
|
||||||
if (db8500_cpufreq_table[i].frequency == rate)
|
if (pos->frequency == rate)
|
||||||
break;
|
break;
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (db8500_cpufreq_table[i].frequency != rate)
|
if (pos->frequency != rate)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Set the new arm opp. */
|
/* 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)
|
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>
|
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||||
*
|
*
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/mfd/core.h>
|
#include <linux/mfd/core.h>
|
||||||
#include <linux/mfd/max14577.h>
|
#include <linux/mfd/max14577.h>
|
||||||
#include <linux/mfd/max14577-private.h>
|
#include <linux/mfd/max14577-private.h>
|
||||||
|
@ -37,7 +38,38 @@ static struct mfd_cell max14577_devs[] = {
|
||||||
{ .name = "max14577-charger", },
|
{ .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) {
|
switch (reg) {
|
||||||
case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3:
|
case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3:
|
||||||
|
@ -48,49 +80,221 @@ static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
|
||||||
return false;
|
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,
|
.reg_bits = 8,
|
||||||
.val_bits = 8,
|
.val_bits = 8,
|
||||||
.volatile_reg = max14577_volatile_reg,
|
.volatile_reg = max14577_muic_volatile_reg,
|
||||||
.max_register = MAX14577_REG_END,
|
.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[] = {
|
static const struct regmap_irq max14577_irqs[] = {
|
||||||
/* INT1 interrupts */
|
/* INT1 interrupts */
|
||||||
{ .reg_offset = 0, .mask = INT1_ADC_MASK, },
|
{ .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
|
||||||
{ .reg_offset = 0, .mask = INT1_ADCLOW_MASK, },
|
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
|
||||||
{ .reg_offset = 0, .mask = INT1_ADCERR_MASK, },
|
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
|
||||||
/* INT2 interrupts */
|
/* INT2 interrupts */
|
||||||
{ .reg_offset = 1, .mask = INT2_CHGTYP_MASK, },
|
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
|
||||||
{ .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, },
|
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
|
||||||
{ .reg_offset = 1, .mask = INT2_DCDTMR_MASK, },
|
{ .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
|
||||||
{ .reg_offset = 1, .mask = INT2_DBCHG_MASK, },
|
{ .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
|
||||||
{ .reg_offset = 1, .mask = INT2_VBVOLT_MASK, },
|
{ .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
|
||||||
/* INT3 interrupts */
|
/* INT3 interrupts */
|
||||||
{ .reg_offset = 2, .mask = INT3_EOC_MASK, },
|
{ .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
|
||||||
{ .reg_offset = 2, .mask = INT3_CGMBC_MASK, },
|
{ .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
|
||||||
{ .reg_offset = 2, .mask = INT3_OVP_MASK, },
|
{ .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
|
||||||
{ .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, },
|
{ .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct regmap_irq_chip max14577_irq_chip = {
|
static const struct regmap_irq_chip max14577_irq_chip = {
|
||||||
.name = "max14577",
|
.name = "max14577",
|
||||||
.status_base = MAX14577_REG_INT1,
|
.status_base = MAX14577_REG_INT1,
|
||||||
.mask_base = MAX14577_REG_INTMASK1,
|
.mask_base = MAX14577_REG_INTMASK1,
|
||||||
.mask_invert = 1,
|
.mask_invert = true,
|
||||||
.num_regs = 3,
|
.num_regs = 3,
|
||||||
.irqs = max14577_irqs,
|
.irqs = max14577_irqs,
|
||||||
.num_irqs = ARRAY_SIZE(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,
|
static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct max14577 *max14577;
|
struct max14577 *max14577;
|
||||||
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
||||||
struct device_node *np = i2c->dev.of_node;
|
struct device_node *np = i2c->dev.of_node;
|
||||||
u8 reg_data;
|
|
||||||
int ret = 0;
|
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) {
|
if (np) {
|
||||||
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
|
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->i2c = i2c;
|
||||||
max14577->irq = i2c->irq;
|
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)) {
|
if (IS_ERR(max14577->regmap)) {
|
||||||
ret = PTR_ERR(max14577->regmap);
|
ret = PTR_ERR(max14577->regmap);
|
||||||
dev_err(max14577->dev, "Failed to allocate register map: %d\n",
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
|
if (np) {
|
||||||
®_data);
|
const struct of_device_id *of_id;
|
||||||
if (ret) {
|
|
||||||
dev_err(max14577->dev, "Device not found on this channel: %d\n",
|
of_id = of_match_device(max14577_dt_match, &i2c->dev);
|
||||||
ret);
|
if (of_id)
|
||||||
return ret;
|
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,
|
ret = regmap_add_irq_chip(max14577->regmap, max14577->irq,
|
||||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
|
irq_flags, 0, irq_chip,
|
||||||
&max14577_irq_chip,
|
|
||||||
&max14577->irq_data);
|
&max14577->irq_data);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mfd_add_devices(max14577->dev, -1, max14577_devs,
|
/* Max77836 specific initialization code (additional regmap) */
|
||||||
ARRAY_SIZE(max14577_devs), NULL, 0,
|
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));
|
regmap_irq_get_domain(max14577->irq_data));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_mfd;
|
goto err_mfd;
|
||||||
|
@ -156,6 +381,9 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_mfd:
|
err_mfd:
|
||||||
|
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
|
||||||
|
max77836_remove(max14577);
|
||||||
|
err_max77836:
|
||||||
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
|
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -167,12 +395,15 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
|
||||||
|
|
||||||
mfd_remove_devices(max14577->dev);
|
mfd_remove_devices(max14577->dev);
|
||||||
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
|
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
|
||||||
|
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
|
||||||
|
max77836_remove(max14577);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id max14577_i2c_id[] = {
|
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);
|
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
|
||||||
|
@ -215,11 +446,6 @@ static int max14577_resume(struct device *dev)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#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 SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume);
|
||||||
|
|
||||||
static struct i2c_driver max14577_i2c_driver = {
|
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)
|
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);
|
return i2c_add_driver(&max14577_i2c_driver);
|
||||||
}
|
}
|
||||||
subsys_initcall(max14577_i2c_init);
|
subsys_initcall(max14577_i2c_init);
|
||||||
|
@ -247,5 +476,5 @@ static void __exit max14577_i2c_exit(void)
|
||||||
module_exit(max14577_i2c_exit);
|
module_exit(max14577_i2c_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
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");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -673,9 +673,13 @@ int mc13xxx_common_init(struct device *dev)
|
||||||
if (mc13xxx->flags & MC13XXX_USE_ADC)
|
if (mc13xxx->flags & MC13XXX_USE_ADC)
|
||||||
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
|
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
|
||||||
|
|
||||||
if (mc13xxx->flags & MC13XXX_USE_CODEC)
|
if (mc13xxx->flags & MC13XXX_USE_CODEC) {
|
||||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
|
if (pdata)
|
||||||
pdata->codec, sizeof(*pdata->codec));
|
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)
|
if (mc13xxx->flags & MC13XXX_USE_RTC)
|
||||||
mc13xxx_add_subdevice(mc13xxx, "%s-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);
|
ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
|
||||||
add_timer(&ucr->sg_timer);
|
add_timer(&ucr->sg_timer);
|
||||||
usb_sg_wait(&ucr->current_sg);
|
usb_sg_wait(&ucr->current_sg);
|
||||||
del_timer(&ucr->sg_timer);
|
del_timer_sync(&ucr->sg_timer);
|
||||||
|
|
||||||
if (act_len)
|
if (act_len)
|
||||||
*act_len = ucr->current_sg.bytes;
|
*act_len = ucr->current_sg.bytes;
|
||||||
|
@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_init_fail;
|
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,
|
ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
|
||||||
ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
|
ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_init_fail;
|
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
|
#ifdef CONFIG_PM
|
||||||
intf->needs_remote_wakeup = 1;
|
intf->needs_remote_wakeup = 1;
|
||||||
usb_enable_autosuspend(usb_dev);
|
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",
|
dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n",
|
||||||
__func__, message.event);
|
__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);
|
mutex_lock(&ucr->dev_mutex);
|
||||||
rtsx_usb_turn_off_led(ucr);
|
rtsx_usb_turn_off_led(ucr);
|
||||||
mutex_unlock(&ucr->dev_mutex);
|
mutex_unlock(&ucr->dev_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include "stmpe.h"
|
#include "stmpe.h"
|
||||||
|
|
||||||
static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
|
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,
|
.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
|
static int
|
||||||
stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
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.data = (void *)id;
|
||||||
i2c_ci.irq = i2c->irq;
|
i2c_ci.irq = i2c->irq;
|
||||||
i2c_ci.client = i2c;
|
i2c_ci.client = i2c;
|
||||||
i2c_ci.dev = &i2c->dev;
|
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)
|
static int stmpe_i2c_remove(struct i2c_client *i2c)
|
||||||
|
@ -89,6 +116,7 @@ static struct i2c_driver stmpe_i2c_driver = {
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.pm = &stmpe_dev_pm_ops,
|
.pm = &stmpe_dev_pm_ops,
|
||||||
#endif
|
#endif
|
||||||
|
.of_match_table = stmpe_of_match,
|
||||||
},
|
},
|
||||||
.probe = stmpe_i2c_probe,
|
.probe = stmpe_i2c_probe,
|
||||||
.remove = stmpe_i2c_remove,
|
.remove = stmpe_i2c_remove,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/mfd/core.h>
|
#include <linux/mfd/core.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
#include "stmpe.h"
|
#include "stmpe.h"
|
||||||
|
|
||||||
static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
|
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)
|
if (blocks & STMPE_BLOCK_GPIO)
|
||||||
mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
|
mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
|
||||||
|
else
|
||||||
|
mask &= ~STMPE1601_SYS_CTRL_ENABLE_GPIO;
|
||||||
|
|
||||||
if (blocks & STMPE_BLOCK_KEYPAD)
|
if (blocks & STMPE_BLOCK_KEYPAD)
|
||||||
mask |= STMPE1601_SYS_CTRL_ENABLE_KPC;
|
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,
|
return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
|
||||||
enable ? mask : 0);
|
enable ? mask : 0);
|
||||||
|
@ -986,9 +996,6 @@ static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np)
|
||||||
int base = 0;
|
int base = 0;
|
||||||
int num_irqs = stmpe->variant->num_irqs;
|
int num_irqs = stmpe->variant->num_irqs;
|
||||||
|
|
||||||
if (!np)
|
|
||||||
base = stmpe->irq_base;
|
|
||||||
|
|
||||||
stmpe->domain = irq_domain_add_simple(np, num_irqs, base,
|
stmpe->domain = irq_domain_add_simple(np, num_irqs, base,
|
||||||
&stmpe_irq_ops, stmpe);
|
&stmpe_irq_ops, stmpe);
|
||||||
if (!stmpe->domain) {
|
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)
|
static int stmpe_add_device(struct stmpe *stmpe, const struct mfd_cell *cell)
|
||||||
{
|
{
|
||||||
return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
|
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)
|
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->dev = ci->dev;
|
||||||
stmpe->client = ci->client;
|
stmpe->client = ci->client;
|
||||||
stmpe->pdata = pdata;
|
stmpe->pdata = pdata;
|
||||||
stmpe->irq_base = pdata->irq_base;
|
|
||||||
stmpe->ci = ci;
|
stmpe->ci = ci;
|
||||||
stmpe->partnum = partnum;
|
stmpe->partnum = partnum;
|
||||||
stmpe->variant = stmpe_variant_info[partnum];
|
stmpe->variant = stmpe_variant_info[partnum];
|
||||||
stmpe->regs = stmpe->variant->regs;
|
stmpe->regs = stmpe->variant->regs;
|
||||||
stmpe->num_gpios = stmpe->variant->num_gpios;
|
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);
|
dev_set_drvdata(stmpe->dev, stmpe);
|
||||||
|
|
||||||
if (ci->init)
|
if (ci->init)
|
||||||
|
@ -1243,6 +1261,11 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
||||||
|
|
||||||
int stmpe_remove(struct stmpe *stmpe)
|
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);
|
mfd_remove_devices(stmpe->dev);
|
||||||
|
|
||||||
return 0;
|
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_GPIO (1 << 3)
|
||||||
#define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1)
|
#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 */
|
/* The 1601/2403 share the same masks */
|
||||||
#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7)
|
#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7)
|
||||||
|
|
|
@ -32,14 +32,6 @@
|
||||||
#define NUM_INT_REG 2
|
#define NUM_INT_REG 2
|
||||||
#define TOTAL_NUM_REG 0x18
|
#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_VAC_STATUS_CHANGE 1
|
||||||
#define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2
|
#define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2
|
||||||
#define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3
|
#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",
|
.name = "tps65090-pmic",
|
||||||
},
|
},
|
||||||
{
|
[CHARGER] = {
|
||||||
.name = "tps65090-charger",
|
.name = "tps65090-charger",
|
||||||
.num_resources = ARRAY_SIZE(charger_resources),
|
.num_resources = ARRAY_SIZE(charger_resources),
|
||||||
.resources = &charger_resources[0],
|
.resources = &charger_resources[0],
|
||||||
|
@ -139,17 +136,26 @@ static struct regmap_irq_chip tps65090_irq_chip = {
|
||||||
.irqs = tps65090_irqs,
|
.irqs = tps65090_irqs,
|
||||||
.num_irqs = ARRAY_SIZE(tps65090_irqs),
|
.num_irqs = ARRAY_SIZE(tps65090_irqs),
|
||||||
.num_regs = NUM_INT_REG,
|
.num_regs = NUM_INT_REG,
|
||||||
.status_base = TPS65090_INT_STS,
|
.status_base = TPS65090_REG_INTR_STS,
|
||||||
.mask_base = TPS65090_INT_MSK,
|
.mask_base = TPS65090_REG_INTR_MASK,
|
||||||
.mask_invert = true,
|
.mask_invert = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool is_volatile_reg(struct device *dev, unsigned int reg)
|
static bool is_volatile_reg(struct device *dev, unsigned int reg)
|
||||||
{
|
{
|
||||||
if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2))
|
/* Nearly all registers have status bits mixed in, except a few */
|
||||||
return true;
|
switch (reg) {
|
||||||
else
|
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 false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct regmap_config tps65090_regmap_config = {
|
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);
|
"IRQ init failed with err: %d\n", ret);
|
||||||
return 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,
|
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:
|
case TPS658623:
|
||||||
name = "TPS658623";
|
name = "TPS658623";
|
||||||
break;
|
break;
|
||||||
|
case TPS658640:
|
||||||
|
case TPS658640v2:
|
||||||
|
name = "TPS658640";
|
||||||
|
break;
|
||||||
case TPS658643:
|
case TPS658643:
|
||||||
name = "TPS658643";
|
name = "TPS658643";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -98,7 +98,11 @@
|
||||||
#define TWL4030_BASEADD_BACKUP 0x0014
|
#define TWL4030_BASEADD_BACKUP 0x0014
|
||||||
#define TWL4030_BASEADD_INT 0x002E
|
#define TWL4030_BASEADD_INT 0x002E
|
||||||
#define TWL4030_BASEADD_PM_MASTER 0x0036
|
#define TWL4030_BASEADD_PM_MASTER 0x0036
|
||||||
|
|
||||||
#define TWL4030_BASEADD_PM_RECEIVER 0x005B
|
#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_RTC 0x001C
|
||||||
#define TWL4030_BASEADD_SECURED_REG 0x0000
|
#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.
|
* 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,
|
* 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.
|
* 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()) {
|
if (twl_class_is_4030()) {
|
||||||
u8 temp;
|
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 | \
|
temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
|
||||||
I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
|
I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
|
||||||
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
|
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) {
|
if (node) {
|
||||||
|
|
|
@ -694,3 +694,10 @@ config MMC_REALTEK_PCI
|
||||||
help
|
help
|
||||||
Say Y here to include driver code to support SD/MMC card interface
|
Say Y here to include driver code to support SD/MMC card interface
|
||||||
of Realtek PCI-E card reader
|
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_WMT) += wmt-sdmmc.o
|
||||||
|
|
||||||
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_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_PLTFM) += sdhci-pltfm.o
|
||||||
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
|
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -28,17 +28,6 @@
|
||||||
|
|
||||||
#include <linux/mfd/tps65090.h>
|
#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_CHARGER_ENABLE BIT(0)
|
||||||
#define TPS65090_VACG BIT(1)
|
#define TPS65090_VACG BIT(1)
|
||||||
#define TPS65090_NOITERM BIT(5)
|
#define TPS65090_NOITERM BIT(5)
|
||||||
|
|
|
@ -266,11 +266,12 @@ config REGULATOR_LP8788
|
||||||
This driver supports LP8788 voltage regulator chip.
|
This driver supports LP8788 voltage regulator chip.
|
||||||
|
|
||||||
config REGULATOR_MAX14577
|
config REGULATOR_MAX14577
|
||||||
tristate "Maxim 14577 regulator"
|
tristate "Maxim 14577/77836 regulator"
|
||||||
depends on MFD_MAX14577
|
depends on MFD_MAX14577
|
||||||
help
|
help
|
||||||
This driver controls a Maxim 14577 regulator via I2C bus.
|
This driver controls a Maxim MAX14577/77836 regulator via I2C bus.
|
||||||
The regulators include safeout LDO and current regulator 'CHARGER'.
|
The MAX14577 regulators include safeout LDO and charger current
|
||||||
|
regulator. The MAX77836 has two additional LDOs.
|
||||||
|
|
||||||
config REGULATOR_MAX1586
|
config REGULATOR_MAX1586
|
||||||
tristate "Maxim 1586/1587 voltage regulator"
|
tristate "Maxim 1586/1587 voltage regulator"
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
@ -178,6 +179,42 @@ static const struct regulator_init_data arizona_ldo1_default = {
|
||||||
.num_consumer_supplies = 1,
|
.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)
|
static int arizona_ldo1_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
|
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;
|
struct arizona_ldo1 *ldo1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
arizona->external_dcvdd = false;
|
||||||
|
|
||||||
ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
|
ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
|
||||||
if (!ldo1)
|
if (!ldo1)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -216,6 +255,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
|
||||||
config.dev = arizona->dev;
|
config.dev = arizona->dev;
|
||||||
config.driver_data = ldo1;
|
config.driver_data = ldo1;
|
||||||
config.regmap = arizona->regmap;
|
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;
|
config.ena_gpio = arizona->pdata.ldoena;
|
||||||
|
|
||||||
if (arizona->pdata.ldo1)
|
if (arizona->pdata.ldo1)
|
||||||
|
@ -223,6 +271,13 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
|
||||||
else
|
else
|
||||||
config.init_data = &ldo1->init_data;
|
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);
|
ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
|
||||||
if (IS_ERR(ldo1->regulator)) {
|
if (IS_ERR(ldo1->regulator)) {
|
||||||
ret = PTR_ERR(ldo1->regulator);
|
ret = PTR_ERR(ldo1->regulator);
|
||||||
|
@ -231,6 +286,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_node_put(config.of_node);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, ldo1);
|
platform_set_drvdata(pdev, ldo1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
@ -195,6 +196,32 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
|
||||||
.num_consumer_supplies = 1,
|
.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)
|
static int arizona_micsupp_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
|
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.driver_data = micsupp;
|
||||||
config.regmap = arizona->regmap;
|
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)
|
if (arizona->pdata.micvdd)
|
||||||
config.init_data = arizona->pdata.micvdd;
|
config.init_data = arizona->pdata.micvdd;
|
||||||
else
|
else
|
||||||
|
@ -253,6 +288,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_node_put(config.of_node);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, micsupp);
|
platform_set_drvdata(pdev, micsupp);
|
||||||
|
|
||||||
return 0;
|
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
|
* Copyright (C) 2013,2014 Samsung Electronics
|
||||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||||
|
@ -22,6 +22,42 @@
|
||||||
#include <linux/mfd/max14577-private.h>
|
#include <linux/mfd/max14577-private.h>
|
||||||
#include <linux/regulator/of_regulator.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)
|
static int max14577_reg_is_enabled(struct regulator_dev *rdev)
|
||||||
{
|
{
|
||||||
int rid = rdev_get_id(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;
|
u8 reg_data;
|
||||||
struct regmap *rmap = rdev->regmap;
|
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)
|
if (rdev_get_id(rdev) != MAX14577_CHARGER)
|
||||||
return -EINVAL;
|
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);
|
max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data);
|
||||||
|
|
||||||
if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
|
if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
|
||||||
return MAX14577_REGULATOR_CURRENT_LIMIT_MIN;
|
return limits->min;
|
||||||
|
|
||||||
reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >>
|
reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >>
|
||||||
CHGCTRL4_MBCICHWRCH_SHIFT);
|
CHGCTRL4_MBCICHWRCH_SHIFT);
|
||||||
return MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
|
return limits->high_start + reg_data * limits->high_step;
|
||||||
reg_data * MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
|
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;
|
int i, current_bits = 0xf;
|
||||||
u8 reg_data;
|
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)
|
if (rdev_get_id(rdev) != MAX14577_CHARGER)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (min_uA > MAX14577_REGULATOR_CURRENT_LIMIT_MAX ||
|
if (min_uA > limits->max || max_uA < limits->min)
|
||||||
max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_MIN)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START) {
|
if (max_uA < limits->high_start) {
|
||||||
/* Less than 200 mA, so set 90mA (turn only Low Bit off) */
|
/*
|
||||||
|
* Less than high_start,
|
||||||
|
* so set the minimal current (turn only Low Bit off)
|
||||||
|
*/
|
||||||
u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT;
|
u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT;
|
||||||
return max14577_update_reg(rdev->regmap,
|
return max14577_update_reg(rdev->regmap,
|
||||||
MAX14577_CHG_REG_CHG_CTRL4,
|
MAX14577_CHG_REG_CHG_CTRL4,
|
||||||
CHGCTRL4_MBCICHWRCL_MASK, reg_data);
|
CHGCTRL4_MBCICHWRCL_MASK, reg_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* max_uA is in range: <LIMIT_HIGH_START, inifinite>, so search for
|
/*
|
||||||
* valid current starting from LIMIT_MAX. */
|
* max_uA is in range: <high_start, inifinite>, so search for
|
||||||
for (i = MAX14577_REGULATOR_CURRENT_LIMIT_MAX;
|
* valid current starting from maximum current.
|
||||||
i >= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START;
|
*/
|
||||||
i -= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP) {
|
for (i = limits->max; i >= limits->high_start; i -= limits->high_step) {
|
||||||
if (i <= max_uA)
|
if (i <= max_uA)
|
||||||
break;
|
break;
|
||||||
current_bits--;
|
current_bits--;
|
||||||
}
|
}
|
||||||
BUG_ON(current_bits < 0); /* Cannot happen */
|
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;
|
reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
|
||||||
/* and set proper High Bits */
|
/* and set proper High Bits */
|
||||||
reg_data |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT;
|
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,
|
.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] = {
|
[MAX14577_SAFEOUT] = {
|
||||||
.name = "SAFEOUT",
|
.name = "SAFEOUT",
|
||||||
.id = MAX14577_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
|
#ifdef CONFIG_OF
|
||||||
static struct of_regulator_match max14577_regulator_matches[] = {
|
static struct of_regulator_match max14577_regulator_matches[] = {
|
||||||
{ .name = "SAFEOUT", },
|
{ .name = "SAFEOUT", },
|
||||||
{ .name = "CHARGER", },
|
{ .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;
|
int ret;
|
||||||
struct device_node *np;
|
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");
|
np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
|
||||||
if (!np) {
|
if (!np) {
|
||||||
|
@ -158,8 +274,19 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
|
switch (dev_type) {
|
||||||
MAX14577_REG_MAX);
|
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)
|
if (ret < 0)
|
||||||
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
|
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
|
||||||
else
|
else
|
||||||
|
@ -170,31 +297,74 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
|
||||||
return ret;
|
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 */
|
#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;
|
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;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_OF */
|
#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)
|
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);
|
struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
|
||||||
int i, ret;
|
int i, ret;
|
||||||
struct regulator_config config = {};
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
config.dev = &pdev->dev;
|
switch (dev_type) {
|
||||||
config.regmap = max14577->regmap;
|
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;
|
struct regulator_dev *regulator;
|
||||||
/*
|
/*
|
||||||
* Index of supported_regulators[] is also the id and must
|
* 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.init_data = pdata->regulators[i].initdata;
|
||||||
config.of_node = pdata->regulators[i].of_node;
|
config.of_node = pdata->regulators[i].of_node;
|
||||||
} else {
|
} else {
|
||||||
config.init_data = match_init_data(i);
|
config.init_data = match_init_data(i, dev_type);
|
||||||
config.of_node = match_of_node(i);
|
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,
|
regulator = devm_regulator_register(&pdev->dev,
|
||||||
&supported_regulators[i], &config);
|
&supported_regulators[i], &config);
|
||||||
if (IS_ERR(regulator)) {
|
if (IS_ERR(regulator)) {
|
||||||
ret = PTR_ERR(regulator);
|
ret = PTR_ERR(regulator);
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Regulator init failed for ID %d with error: %d\n",
|
"Regulator init failed for %d/%s with error: %d\n",
|
||||||
i, ret);
|
i, supported_regulators[i].name, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,20 +424,41 @@ static int max14577_regulator_probe(struct platform_device *pdev)
|
||||||
return ret;
|
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 = {
|
static struct platform_driver max14577_regulator_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "max14577-regulator",
|
.name = "max14577-regulator",
|
||||||
},
|
},
|
||||||
.probe = max14577_regulator_probe,
|
.probe = max14577_regulator_probe,
|
||||||
|
.id_table = max14577_regulator_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init max14577_regulator_init(void)
|
static int __init max14577_regulator_init(void)
|
||||||
{
|
{
|
||||||
|
/* Check for valid values for charger */
|
||||||
BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
|
BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
|
||||||
MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
|
MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
|
||||||
MAX14577_REGULATOR_CURRENT_LIMIT_MAX);
|
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);
|
return platform_driver_register(&max14577_regulator_driver);
|
||||||
}
|
}
|
||||||
|
@ -264,6 +471,6 @@ static void __exit max14577_regulator_exit(void)
|
||||||
module_exit(max14577_regulator_exit);
|
module_exit(max14577_regulator_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
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_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:max14577-regulator");
|
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;
|
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,
|
.list_voltage = regulator_list_voltage_table,
|
||||||
.map_voltage = regulator_map_voltage_ascend,
|
.map_voltage = regulator_map_voltage_ascend,
|
||||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
@ -79,6 +79,16 @@ static struct regulator_ops tps6586x_regulator_ops = {
|
||||||
.disable = regulator_disable_regmap,
|
.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 = {
|
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,
|
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[] = {
|
static const unsigned int tps658643_sm2_voltages[] = {
|
||||||
1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000,
|
1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000,
|
||||||
1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000,
|
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,
|
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) \
|
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
|
||||||
.desc = { \
|
.desc = { \
|
||||||
.supply_name = _pin_name, \
|
.supply_name = _pin_name, \
|
||||||
.name = "REG-" #_id, \
|
.name = "REG-" #_id, \
|
||||||
.ops = &tps6586x_regulator_ops, \
|
.ops = &tps6586x_## _ops ## _regulator_ops, \
|
||||||
.type = REGULATOR_VOLTAGE, \
|
.type = REGULATOR_VOLTAGE, \
|
||||||
.id = TPS6586X_ID_##_id, \
|
.id = TPS6586X_ID_##_id, \
|
||||||
.n_voltages = ARRAY_SIZE(vdata##_voltages), \
|
.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, \
|
#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \
|
||||||
ereg0, ebit0, ereg1, ebit1) \
|
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) \
|
ereg0, ebit0, ereg1, ebit1, 0, 0) \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
|
#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
|
||||||
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
|
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) \
|
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +235,26 @@ static struct tps6586x_regulator tps658623_regulator[] = {
|
||||||
END, 7),
|
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[] = {
|
static struct tps6586x_regulator tps658643_regulator[] = {
|
||||||
TPS6586X_LDO(SM_2, "vin-sm2", tps658643_sm2, SUPPLYV2, 0, 5, ENC, 7,
|
TPS6586X_LDO(SM_2, "vin-sm2", tps658643_sm2, SUPPLYV2, 0, 5, ENC, 7,
|
||||||
END, 7),
|
END, 7),
|
||||||
|
@ -295,6 +343,11 @@ static struct tps6586x_regulator *find_regulator_info(int id, int version)
|
||||||
table = tps658623_regulator;
|
table = tps658623_regulator;
|
||||||
num = ARRAY_SIZE(tps658623_regulator);
|
num = ARRAY_SIZE(tps658623_regulator);
|
||||||
break;
|
break;
|
||||||
|
case TPS658640:
|
||||||
|
case TPS658640v2:
|
||||||
|
table = tps658640_regulator;
|
||||||
|
num = ARRAY_SIZE(tps658640_regulator);
|
||||||
|
break;
|
||||||
case TPS658643:
|
case TPS658643:
|
||||||
table = tps658643_regulator;
|
table = tps658643_regulator;
|
||||||
num = ARRAY_SIZE(tps658643_regulator);
|
num = ARRAY_SIZE(tps658643_regulator);
|
||||||
|
|
|
@ -468,6 +468,27 @@ struct cpufreq_frequency_table {
|
||||||
* order */
|
* 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,
|
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
|
||||||
struct cpufreq_frequency_table *table);
|
struct cpufreq_frequency_table *table);
|
||||||
|
|
||||||
|
|
|
@ -124,4 +124,7 @@ int wm5102_patch(struct arizona *arizona);
|
||||||
int wm5110_patch(struct arizona *arizona);
|
int wm5110_patch(struct arizona *arizona);
|
||||||
int wm8997_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
|
#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>
|
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||||
*
|
*
|
||||||
|
@ -22,9 +22,19 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/regmap.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 {
|
enum max14577_reg {
|
||||||
MAX14577_REG_DEVICEID = 0x00,
|
MAX14577_REG_DEVICEID = 0x00,
|
||||||
MAX14577_REG_INT1 = 0x01,
|
MAX14577_REG_INT1 = 0x01,
|
||||||
|
@ -74,20 +84,22 @@ enum max14577_muic_charger_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* MAX14577 interrupts */
|
/* MAX14577 interrupts */
|
||||||
#define INT1_ADC_MASK (0x1 << 0)
|
#define MAX14577_INT1_ADC_MASK BIT(0)
|
||||||
#define INT1_ADCLOW_MASK (0x1 << 1)
|
#define MAX14577_INT1_ADCLOW_MASK BIT(1)
|
||||||
#define INT1_ADCERR_MASK (0x1 << 2)
|
#define MAX14577_INT1_ADCERR_MASK BIT(2)
|
||||||
|
#define MAX77836_INT1_ADC1K_MASK BIT(3)
|
||||||
|
|
||||||
#define INT2_CHGTYP_MASK (0x1 << 0)
|
#define MAX14577_INT2_CHGTYP_MASK BIT(0)
|
||||||
#define INT2_CHGDETRUN_MASK (0x1 << 1)
|
#define MAX14577_INT2_CHGDETRUN_MASK BIT(1)
|
||||||
#define INT2_DCDTMR_MASK (0x1 << 2)
|
#define MAX14577_INT2_DCDTMR_MASK BIT(2)
|
||||||
#define INT2_DBCHG_MASK (0x1 << 3)
|
#define MAX14577_INT2_DBCHG_MASK BIT(3)
|
||||||
#define INT2_VBVOLT_MASK (0x1 << 4)
|
#define MAX14577_INT2_VBVOLT_MASK BIT(4)
|
||||||
|
#define MAX77836_INT2_VIDRM_MASK BIT(5)
|
||||||
|
|
||||||
#define INT3_EOC_MASK (0x1 << 0)
|
#define MAX14577_INT3_EOC_MASK BIT(0)
|
||||||
#define INT3_CGMBC_MASK (0x1 << 1)
|
#define MAX14577_INT3_CGMBC_MASK BIT(1)
|
||||||
#define INT3_OVP_MASK (0x1 << 2)
|
#define MAX14577_INT3_OVP_MASK BIT(2)
|
||||||
#define INT3_MBCCHGERR_MASK (0x1 << 3)
|
#define MAX14577_INT3_MBCCHGERR_MASK BIT(3)
|
||||||
|
|
||||||
/* MAX14577 DEVICE ID register */
|
/* MAX14577 DEVICE ID register */
|
||||||
#define DEVID_VENDORID_SHIFT 0
|
#define DEVID_VENDORID_SHIFT 0
|
||||||
|
@ -99,9 +111,11 @@ enum max14577_muic_charger_type {
|
||||||
#define STATUS1_ADC_SHIFT 0
|
#define STATUS1_ADC_SHIFT 0
|
||||||
#define STATUS1_ADCLOW_SHIFT 5
|
#define STATUS1_ADCLOW_SHIFT 5
|
||||||
#define STATUS1_ADCERR_SHIFT 6
|
#define STATUS1_ADCERR_SHIFT 6
|
||||||
|
#define MAX77836_STATUS1_ADC1K_SHIFT 7
|
||||||
#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
|
#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
|
||||||
#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT)
|
#define STATUS1_ADCLOW_MASK BIT(STATUS1_ADCLOW_SHIFT)
|
||||||
#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT)
|
#define STATUS1_ADCERR_MASK BIT(STATUS1_ADCERR_SHIFT)
|
||||||
|
#define MAX77836_STATUS1_ADC1K_MASK BIT(MAX77836_STATUS1_ADC1K_SHIFT)
|
||||||
|
|
||||||
/* MAX14577 STATUS2 register */
|
/* MAX14577 STATUS2 register */
|
||||||
#define STATUS2_CHGTYP_SHIFT 0
|
#define STATUS2_CHGTYP_SHIFT 0
|
||||||
|
@ -109,11 +123,13 @@ enum max14577_muic_charger_type {
|
||||||
#define STATUS2_DCDTMR_SHIFT 4
|
#define STATUS2_DCDTMR_SHIFT 4
|
||||||
#define STATUS2_DBCHG_SHIFT 5
|
#define STATUS2_DBCHG_SHIFT 5
|
||||||
#define STATUS2_VBVOLT_SHIFT 6
|
#define STATUS2_VBVOLT_SHIFT 6
|
||||||
|
#define MAX77836_STATUS2_VIDRM_SHIFT 7
|
||||||
#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
|
#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
|
||||||
#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT)
|
#define STATUS2_CHGDETRUN_MASK BIT(STATUS2_CHGDETRUN_SHIFT)
|
||||||
#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT)
|
#define STATUS2_DCDTMR_MASK BIT(STATUS2_DCDTMR_SHIFT)
|
||||||
#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT)
|
#define STATUS2_DBCHG_MASK BIT(STATUS2_DBCHG_SHIFT)
|
||||||
#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT)
|
#define STATUS2_VBVOLT_MASK BIT(STATUS2_VBVOLT_SHIFT)
|
||||||
|
#define MAX77836_STATUS2_VIDRM_MASK BIT(MAX77836_STATUS2_VIDRM_SHIFT)
|
||||||
|
|
||||||
/* MAX14577 CONTROL1 register */
|
/* MAX14577 CONTROL1 register */
|
||||||
#define COMN1SW_SHIFT 0
|
#define COMN1SW_SHIFT 0
|
||||||
|
@ -122,8 +138,8 @@ enum max14577_muic_charger_type {
|
||||||
#define IDBEN_SHIFT 7
|
#define IDBEN_SHIFT 7
|
||||||
#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
|
#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
|
||||||
#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
|
#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
|
||||||
#define MICEN_MASK (0x1 << MICEN_SHIFT)
|
#define MICEN_MASK BIT(MICEN_SHIFT)
|
||||||
#define IDBEN_MASK (0x1 << IDBEN_SHIFT)
|
#define IDBEN_MASK BIT(IDBEN_SHIFT)
|
||||||
#define CLEAR_IDBEN_MICEN_MASK (COMN1SW_MASK | COMP2SW_MASK)
|
#define CLEAR_IDBEN_MICEN_MASK (COMN1SW_MASK | COMP2SW_MASK)
|
||||||
#define CTRL1_SW_USB ((1 << COMP2SW_SHIFT) \
|
#define CTRL1_SW_USB ((1 << COMP2SW_SHIFT) \
|
||||||
| (1 << COMN1SW_SHIFT))
|
| (1 << COMN1SW_SHIFT))
|
||||||
|
@ -143,14 +159,14 @@ enum max14577_muic_charger_type {
|
||||||
#define CTRL2_ACCDET_SHIFT (5)
|
#define CTRL2_ACCDET_SHIFT (5)
|
||||||
#define CTRL2_USBCPINT_SHIFT (6)
|
#define CTRL2_USBCPINT_SHIFT (6)
|
||||||
#define CTRL2_RCPS_SHIFT (7)
|
#define CTRL2_RCPS_SHIFT (7)
|
||||||
#define CTRL2_LOWPWR_MASK (0x1 << CTRL2_LOWPWR_SHIFT)
|
#define CTRL2_LOWPWR_MASK BIT(CTRL2_LOWPWR_SHIFT)
|
||||||
#define CTRL2_ADCEN_MASK (0x1 << CTRL2_ADCEN_SHIFT)
|
#define CTRL2_ADCEN_MASK BIT(CTRL2_ADCEN_SHIFT)
|
||||||
#define CTRL2_CPEN_MASK (0x1 << CTRL2_CPEN_SHIFT)
|
#define CTRL2_CPEN_MASK BIT(CTRL2_CPEN_SHIFT)
|
||||||
#define CTRL2_SFOUTASRT_MASK (0x1 << CTRL2_SFOUTASRT_SHIFT)
|
#define CTRL2_SFOUTASRT_MASK BIT(CTRL2_SFOUTASRT_SHIFT)
|
||||||
#define CTRL2_SFOUTORD_MASK (0x1 << CTRL2_SFOUTORD_SHIFT)
|
#define CTRL2_SFOUTORD_MASK BIT(CTRL2_SFOUTORD_SHIFT)
|
||||||
#define CTRL2_ACCDET_MASK (0x1 << CTRL2_ACCDET_SHIFT)
|
#define CTRL2_ACCDET_MASK BIT(CTRL2_ACCDET_SHIFT)
|
||||||
#define CTRL2_USBCPINT_MASK (0x1 << CTRL2_USBCPINT_SHIFT)
|
#define CTRL2_USBCPINT_MASK BIT(CTRL2_USBCPINT_SHIFT)
|
||||||
#define CTRL2_RCPS_MASK (0x1 << CTR2_RCPS_SHIFT)
|
#define CTRL2_RCPS_MASK BIT(CTRL2_RCPS_SHIFT)
|
||||||
|
|
||||||
#define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \
|
#define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \
|
||||||
(0 << CTRL2_LOWPWR_SHIFT))
|
(0 << CTRL2_LOWPWR_SHIFT))
|
||||||
|
@ -198,14 +214,14 @@ enum max14577_charger_reg {
|
||||||
#define CDETCTRL1_DBEXIT_SHIFT 5
|
#define CDETCTRL1_DBEXIT_SHIFT 5
|
||||||
#define CDETCTRL1_DBIDLE_SHIFT 6
|
#define CDETCTRL1_DBIDLE_SHIFT 6
|
||||||
#define CDETCTRL1_CDPDET_SHIFT 7
|
#define CDETCTRL1_CDPDET_SHIFT 7
|
||||||
#define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT)
|
#define CDETCTRL1_CHGDETEN_MASK BIT(CDETCTRL1_CHGDETEN_SHIFT)
|
||||||
#define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT)
|
#define CDETCTRL1_CHGTYPMAN_MASK BIT(CDETCTRL1_CHGTYPMAN_SHIFT)
|
||||||
#define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT)
|
#define CDETCTRL1_DCDEN_MASK BIT(CDETCTRL1_DCDEN_SHIFT)
|
||||||
#define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT)
|
#define CDETCTRL1_DCD2SCT_MASK BIT(CDETCTRL1_DCD2SCT_SHIFT)
|
||||||
#define CDETCTRL1_DCHKTM_MASK (0x1 << CDETCTRL1_DCHKTM_SHIFT)
|
#define CDETCTRL1_DCHKTM_MASK BIT(CDETCTRL1_DCHKTM_SHIFT)
|
||||||
#define CDETCTRL1_DBEXIT_MASK (0x1 << CDETCTRL1_DBEXIT_SHIFT)
|
#define CDETCTRL1_DBEXIT_MASK BIT(CDETCTRL1_DBEXIT_SHIFT)
|
||||||
#define CDETCTRL1_DBIDLE_MASK (0x1 << CDETCTRL1_DBIDLE_SHIFT)
|
#define CDETCTRL1_DBIDLE_MASK BIT(CDETCTRL1_DBIDLE_SHIFT)
|
||||||
#define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT)
|
#define CDETCTRL1_CDPDET_MASK BIT(CDETCTRL1_CDPDET_SHIFT)
|
||||||
|
|
||||||
/* MAX14577 CHGCTRL1 register */
|
/* MAX14577 CHGCTRL1 register */
|
||||||
#define CHGCTRL1_TCHW_SHIFT 4
|
#define CHGCTRL1_TCHW_SHIFT 4
|
||||||
|
@ -213,9 +229,9 @@ enum max14577_charger_reg {
|
||||||
|
|
||||||
/* MAX14577 CHGCTRL2 register */
|
/* MAX14577 CHGCTRL2 register */
|
||||||
#define CHGCTRL2_MBCHOSTEN_SHIFT 6
|
#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_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 */
|
/* MAX14577 CHGCTRL3 register */
|
||||||
#define CHGCTRL3_MBCCVWRC_SHIFT 0
|
#define CHGCTRL3_MBCCVWRC_SHIFT 0
|
||||||
|
@ -225,7 +241,7 @@ enum max14577_charger_reg {
|
||||||
#define CHGCTRL4_MBCICHWRCH_SHIFT 0
|
#define CHGCTRL4_MBCICHWRCH_SHIFT 0
|
||||||
#define CHGCTRL4_MBCICHWRCH_MASK (0xf << CHGCTRL4_MBCICHWRCH_SHIFT)
|
#define CHGCTRL4_MBCICHWRCH_MASK (0xf << CHGCTRL4_MBCICHWRCH_SHIFT)
|
||||||
#define CHGCTRL4_MBCICHWRCL_SHIFT 4
|
#define CHGCTRL4_MBCICHWRCL_SHIFT 4
|
||||||
#define CHGCTRL4_MBCICHWRCL_MASK (0x1 << CHGCTRL4_MBCICHWRCL_SHIFT)
|
#define CHGCTRL4_MBCICHWRCL_MASK BIT(CHGCTRL4_MBCICHWRCL_SHIFT)
|
||||||
|
|
||||||
/* MAX14577 CHGCTRL5 register */
|
/* MAX14577 CHGCTRL5 register */
|
||||||
#define CHGCTRL5_EOCS_SHIFT 0
|
#define CHGCTRL5_EOCS_SHIFT 0
|
||||||
|
@ -233,7 +249,7 @@ enum max14577_charger_reg {
|
||||||
|
|
||||||
/* MAX14577 CHGCTRL6 register */
|
/* MAX14577 CHGCTRL6 register */
|
||||||
#define CHGCTRL6_AUTOSTOP_SHIFT 5
|
#define CHGCTRL6_AUTOSTOP_SHIFT 5
|
||||||
#define CHGCTRL6_AUTOSTOP_MASK (0x1 << CHGCTRL6_AUTOSTOP_SHIFT)
|
#define CHGCTRL6_AUTOSTOP_MASK BIT(CHGCTRL6_AUTOSTOP_SHIFT)
|
||||||
|
|
||||||
/* MAX14577 CHGCTRL7 register */
|
/* MAX14577 CHGCTRL7 register */
|
||||||
#define CHGCTRL7_OTPCGHCVS_SHIFT 0
|
#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_HIGH_STEP 50000
|
||||||
#define MAX14577_REGULATOR_CURRENT_LIMIT_MAX 950000
|
#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 */
|
/* MAX14577 regulator SFOUT LDO voltage, fixed, uV */
|
||||||
#define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000
|
#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 {
|
enum max14577_irq {
|
||||||
/* INT1 */
|
/* INT1 */
|
||||||
MAX14577_IRQ_INT1_ADC,
|
MAX14577_IRQ_INT1_ADC,
|
||||||
MAX14577_IRQ_INT1_ADCLOW,
|
MAX14577_IRQ_INT1_ADCLOW,
|
||||||
MAX14577_IRQ_INT1_ADCERR,
|
MAX14577_IRQ_INT1_ADCERR,
|
||||||
|
MAX77836_IRQ_INT1_ADC1K,
|
||||||
|
|
||||||
/* INT2 */
|
/* INT2 */
|
||||||
MAX14577_IRQ_INT2_CHGTYP,
|
MAX14577_IRQ_INT2_CHGTYP,
|
||||||
|
@ -260,6 +373,7 @@ enum max14577_irq {
|
||||||
MAX14577_IRQ_INT2_DCDTMR,
|
MAX14577_IRQ_INT2_DCDTMR,
|
||||||
MAX14577_IRQ_INT2_DBCHG,
|
MAX14577_IRQ_INT2_DBCHG,
|
||||||
MAX14577_IRQ_INT2_VBVOLT,
|
MAX14577_IRQ_INT2_VBVOLT,
|
||||||
|
MAX77836_IRQ_INT2_VIDRM,
|
||||||
|
|
||||||
/* INT3 */
|
/* INT3 */
|
||||||
MAX14577_IRQ_INT3_EOC,
|
MAX14577_IRQ_INT3_EOC,
|
||||||
|
@ -267,21 +381,25 @@ enum max14577_irq {
|
||||||
MAX14577_IRQ_INT3_OVP,
|
MAX14577_IRQ_INT3_OVP,
|
||||||
MAX14577_IRQ_INT3_MBCCHGERR,
|
MAX14577_IRQ_INT3_MBCCHGERR,
|
||||||
|
|
||||||
|
/* TOPSYS_INT, only MAX77836 */
|
||||||
|
MAX77836_IRQ_TOPSYS_T140C,
|
||||||
|
MAX77836_IRQ_TOPSYS_T120C,
|
||||||
|
|
||||||
MAX14577_IRQ_NUM,
|
MAX14577_IRQ_NUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct max14577 {
|
struct max14577 {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct i2c_client *i2c; /* Slave addr = 0x4A */
|
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;
|
int irq;
|
||||||
|
|
||||||
/* Device ID */
|
|
||||||
u8 vendor_id; /* Vendor Identification */
|
|
||||||
u8 device_id; /* Chip Version */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* MAX14577 shared regmap API function */
|
/* 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>
|
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||||
*
|
*
|
||||||
|
@ -20,6 +20,9 @@
|
||||||
* MAX14577 has MUIC, Charger devices.
|
* MAX14577 has MUIC, Charger devices.
|
||||||
* The devices share the same I2C bus and interrupt line
|
* The devices share the same I2C bus and interrupt line
|
||||||
* included in this mfd driver.
|
* included in this mfd driver.
|
||||||
|
*
|
||||||
|
* MAX77836 has additional PMIC and Fuel-Gauge on different I2C slave
|
||||||
|
* addresses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MAX14577_H__
|
#ifndef __MAX14577_H__
|
||||||
|
@ -32,7 +35,17 @@ enum max14577_regulators {
|
||||||
MAX14577_SAFEOUT = 0,
|
MAX14577_SAFEOUT = 0,
|
||||||
MAX14577_CHARGER,
|
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 {
|
struct max14577_regulator_platform_data {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
struct device;
|
struct device;
|
||||||
|
struct regulator;
|
||||||
|
|
||||||
enum stmpe_block {
|
enum stmpe_block {
|
||||||
STMPE_BLOCK_GPIO = 1 << 0,
|
STMPE_BLOCK_GPIO = 1 << 0,
|
||||||
|
@ -62,6 +63,8 @@ struct stmpe_client_info;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct stmpe - STMPE MFD structure
|
* struct stmpe - STMPE MFD structure
|
||||||
|
* @vcc: optional VCC regulator
|
||||||
|
* @vio: optional VIO regulator
|
||||||
* @lock: lock protecting I/O operations
|
* @lock: lock protecting I/O operations
|
||||||
* @irq_lock: IRQ bus lock
|
* @irq_lock: IRQ bus lock
|
||||||
* @dev: device, mostly for dev_dbg()
|
* @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
|
* @regs: list of addresses of registers which are at different addresses on
|
||||||
* different variants. Indexed by one of STMPE_IDX_*.
|
* different variants. Indexed by one of STMPE_IDX_*.
|
||||||
* @irq: irq number for stmpe
|
* @irq: irq number for stmpe
|
||||||
* @irq_base: starting IRQ number for internal IRQs
|
|
||||||
* @num_gpios: number of gpios, differs for variants
|
* @num_gpios: number of gpios, differs for variants
|
||||||
* @ier: cache of IER registers for bus_lock
|
* @ier: cache of IER registers for bus_lock
|
||||||
* @oldier: cache of IER registers for bus_lock
|
* @oldier: cache of IER registers for bus_lock
|
||||||
* @pdata: platform data
|
* @pdata: platform data
|
||||||
*/
|
*/
|
||||||
struct stmpe {
|
struct stmpe {
|
||||||
|
struct regulator *vcc;
|
||||||
|
struct regulator *vio;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct mutex irq_lock;
|
struct mutex irq_lock;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -91,7 +95,6 @@ struct stmpe {
|
||||||
const u8 *regs;
|
const u8 *regs;
|
||||||
|
|
||||||
int irq;
|
int irq;
|
||||||
int irq_base;
|
|
||||||
int num_gpios;
|
int num_gpios;
|
||||||
u8 ier[2];
|
u8 ier[2];
|
||||||
u8 oldier[2];
|
u8 oldier[2];
|
||||||
|
@ -132,8 +135,6 @@ struct stmpe_keypad_platform_data {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct stmpe_gpio_platform_data - STMPE GPIO 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
|
* @norequest_mask: bitmask specifying which GPIOs should _not_ be
|
||||||
* requestable due to different usage (e.g. touch, keypad)
|
* requestable due to different usage (e.g. touch, keypad)
|
||||||
* STMPE_GPIO_NOREQ_* macros can be used here.
|
* STMPE_GPIO_NOREQ_* macros can be used here.
|
||||||
|
@ -141,7 +142,6 @@ struct stmpe_keypad_platform_data {
|
||||||
* @remove: board specific remove callback
|
* @remove: board specific remove callback
|
||||||
*/
|
*/
|
||||||
struct stmpe_gpio_platform_data {
|
struct stmpe_gpio_platform_data {
|
||||||
int gpio_base;
|
|
||||||
unsigned norequest_mask;
|
unsigned norequest_mask;
|
||||||
void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
|
void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
|
||||||
void (*remove)(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
|
* @irq_trigger: IRQ trigger to use for the interrupt to the host
|
||||||
* @autosleep: bool to enable/disable stmpe autosleep
|
* @autosleep: bool to enable/disable stmpe autosleep
|
||||||
* @autosleep_timeout: inactivity timeout in milliseconds for 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_over_gpio: true if gpio is used to get irq
|
||||||
* @irq_gpio: gpio number over which irq will be requested (significant only if
|
* @irq_gpio: gpio number over which irq will be requested (significant only if
|
||||||
* irq_over_gpio is true)
|
* irq_over_gpio is true)
|
||||||
|
@ -207,7 +205,6 @@ struct stmpe_ts_platform_data {
|
||||||
struct stmpe_platform_data {
|
struct stmpe_platform_data {
|
||||||
int id;
|
int id;
|
||||||
unsigned int blocks;
|
unsigned int blocks;
|
||||||
int irq_base;
|
|
||||||
unsigned int irq_trigger;
|
unsigned int irq_trigger;
|
||||||
bool autosleep;
|
bool autosleep;
|
||||||
bool irq_over_gpio;
|
bool irq_over_gpio;
|
||||||
|
@ -219,10 +216,4 @@ struct stmpe_platform_data {
|
||||||
struct stmpe_ts_platform_data *ts;
|
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
|
#endif
|
||||||
|
|
|
@ -64,6 +64,20 @@ enum {
|
||||||
TPS65090_REGULATOR_MAX,
|
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 tps65090 {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct regmap *rmap;
|
struct regmap *rmap;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#define TPS658621A 0x15
|
#define TPS658621A 0x15
|
||||||
#define TPS658621CD 0x2c
|
#define TPS658621CD 0x2c
|
||||||
#define TPS658623 0x1b
|
#define TPS658623 0x1b
|
||||||
|
#define TPS658640 0x01
|
||||||
|
#define TPS658640v2 0x02
|
||||||
#define TPS658643 0x03
|
#define TPS658643 0x03
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*/
|
*/
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/mfd/mc13xxx.h>
|
#include <linux/mfd/mc13xxx.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
|
@ -750,6 +751,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct mc13783_priv *priv;
|
struct mc13783_priv *priv;
|
||||||
struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
|
struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
struct device_node *np;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
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->adc_ssi_port = pdata->adc_ssi_port;
|
||||||
priv->dac_ssi_port = pdata->dac_ssi_port;
|
priv->dac_ssi_port = pdata->dac_ssi_port;
|
||||||
} else {
|
} 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);
|
dev_set_drvdata(&pdev->dev, priv);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче