Commit 28fee3fa authored by Lee Jones's avatar Lee Jones

Merge branches 'ib-from-asoc-3.16', 'ib-from-pm-3.16',...

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
......@@ -228,3 +228,22 @@ is the corresponding frequency table helper for the ->target
stage. Just pass the values to this function, and the unsigned int
index returns the number of the frequency table entry which contains
the frequency the CPU shall be set to.
The following macros can be used as iterators over cpufreq_frequency_table:
cpufreq_for_each_entry(pos, table) - iterates over all entries of frequency
table.
cpufreq-for_each_valid_entry(pos, table) - iterates over all entries,
excluding CPUFREQ_ENTRY_INVALID frequencies.
Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and
"table" - the cpufreq_frequency_table * you want to iterate over.
For example:
struct cpufreq_frequency_table *pos, *driver_freq_table;
cpufreq_for_each_entry(pos, driver_freq_table) {
/* Do something with pos */
pos->frequency = ...
}
......@@ -10,6 +10,9 @@ Optional properties:
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
Sub-nodes:
- codec: Contain the Audio Codec node.
- adc-port: Contain PMIC SSI port number used for ADC.
- dac-port: Contain PMIC SSI port number used for DAC.
- leds : Contain the led nodes and initial register values in property
"led-control". Number of register depends of used IC, for MC13783 is 6,
for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of
......
......@@ -1092,20 +1092,21 @@ int da850_register_cpufreq(char *async_clk)
static int da850_round_armrate(struct clk *clk, unsigned long rate)
{
int i, ret = 0, diff;
int ret = 0, diff;
unsigned int best = (unsigned int) -1;
struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
struct cpufreq_frequency_table *pos;
rate /= 1000; /* convert to kHz */
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
diff = table[i].frequency - rate;
cpufreq_for_each_entry(pos, table) {
diff = pos->frequency - rate;
if (diff < 0)
diff = -diff;
if (diff < best) {
best = diff;
ret = table[i].frequency;
ret = pos->frequency;
}
}
......
......@@ -46,15 +46,8 @@
static bool is_offset_valid;
static u8 smps_offset;
/*
* Flag to ensure Smartreflex bit in TWL
* being cleared in board file is not overwritten.
*/
static bool __initdata twl_sr_enable_autoinit;
#define TWL4030_DCDC_GLOBAL_CFG 0x06
#define REG_SMPS_OFFSET 0xE0
#define SMARTREFLEX_ENABLE BIT(3)
static unsigned long twl4030_vsel_to_uv(const u8 vsel)
{
......@@ -251,18 +244,6 @@ int __init omap3_twl_init(void)
if (!cpu_is_omap34xx())
return -ENODEV;
/*
* The smartreflex bit on twl4030 specifies if the setting of voltage
* is done over the I2C_SR path. Since this setting is independent of
* the actual usage of smartreflex AVS module, we enable TWL SR bit
* by default irrespective of whether smartreflex AVS module is enabled
* on the OMAP side or not. This is because without this bit enabled,
* the voltage scaling through vp forceupdate/bypass mechanism of
* voltage scaling will not function on TWL over I2C_SR.
*/
if (!twl_sr_enable_autoinit)
omap3_twl_set_sr_bit(true);
voltdm = voltdm_lookup("mpu_iva");
omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic);
......@@ -271,44 +252,3 @@ int __init omap3_twl_init(void)
return 0;
}
/**
* omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL
* @enable: enable SR mode in twl or not
*
* If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure
* voltage scaling through OMAP SR works. Else, the smartreflex bit
* on twl4030 is cleared as there are platforms which use OMAP3 and T2 but
* use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct
* Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages,
* in those scenarios this bit is to be cleared (enable = false).
*
* Returns 0 on success, error is returned if I2C read/write fails.
*/
int __init omap3_twl_set_sr_bit(bool enable)
{
u8 temp;
int ret;
if (twl_sr_enable_autoinit)
pr_warning("%s: unexpected multiple calls\n", __func__);
ret = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
TWL4030_DCDC_GLOBAL_CFG);
if (ret)
goto err;
if (enable)
temp |= SMARTREFLEX_ENABLE;
else
temp &= ~SMARTREFLEX_ENABLE;
ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
TWL4030_DCDC_GLOBAL_CFG);
if (!ret) {
twl_sr_enable_autoinit = true;
return 0;
}
err:
pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret);
return ret;
}
......@@ -213,7 +213,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
{
int i;
struct cpufreq_frequency_table *pos;
struct acpi_processor_performance *perf;
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
......@@ -223,10 +223,9 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
perf = data->acpi_data;
for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (msr == perf->states[data->freq_table[i].driver_data].status)
return data->freq_table[i].frequency;
}
cpufreq_for_each_entry(pos, data->freq_table)
if (msr == perf->states[pos->driver_data].status)
return pos->frequency;
return data->freq_table[0].frequency;
}
......
......@@ -226,22 +226,22 @@ static inline u32 get_table_count(struct cpufreq_frequency_table *table)
/* get the minimum frequency in the cpufreq_frequency_table */
static inline u32 get_table_min(struct cpufreq_frequency_table *table)
{
int i;
struct cpufreq_frequency_table *pos;
uint32_t min_freq = ~0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
if (table[i].frequency < min_freq)
min_freq = table[i].frequency;
cpufreq_for_each_entry(pos, table)
if (pos->frequency < min_freq)
min_freq = pos->frequency;
return min_freq;
}
/* get the maximum frequency in the cpufreq_frequency_table */
static inline u32 get_table_max(struct cpufreq_frequency_table *table)
{
int i;
struct cpufreq_frequency_table *pos;
uint32_t max_freq = 0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
if (table[i].frequency > max_freq)
max_freq = table[i].frequency;
cpufreq_for_each_entry(pos, table)
if (pos->frequency > max_freq)
max_freq = pos->frequency;
return max_freq;
}
......
......@@ -237,6 +237,17 @@ void cpufreq_cpu_put(struct cpufreq_policy *policy)
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
bool cpufreq_next_valid(struct cpufreq_frequency_table **pos)
{
while ((*pos)->frequency != CPUFREQ_TABLE_END)
if ((*pos)->frequency != CPUFREQ_ENTRY_INVALID)
return true;
else
(*pos)++;
return false;
}
EXPORT_SYMBOL_GPL(cpufreq_next_valid);
/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
*********************************************************************/
......
......@@ -182,11 +182,11 @@ static void cpufreq_stats_free_table(unsigned int cpu)
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
{
unsigned int i, j, count = 0, ret = 0;
unsigned int i, count = 0, ret = 0;
struct cpufreq_stats *stat;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
struct cpufreq_frequency_table *table;
struct cpufreq_frequency_table *pos, *table;
table = cpufreq_frequency_get_table(cpu);
if (unlikely(!table))
......@@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
stat->cpu = cpu;
per_cpu(cpufreq_stats_table, cpu) = stat;
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table)
count++;
}
alloc_size = count * sizeof(int) + count * sizeof(u64);
......@@ -228,15 +224,11 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat->trans_table = stat->freq_table + count;
#endif
j = 0;
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
if (freq_table_get_index(stat, freq) == -1)
stat->freq_table[j++] = freq;
}
stat->state_num = j;
i = 0;
cpufreq_for_each_valid_entry(pos, table)
if (freq_table_get_index(stat, pos->frequency) == -1)
stat->freq_table[i++] = pos->frequency;
stat->state_num = i;
spin_lock(&cpufreq_stats_lock);
stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur);
......
......@@ -45,7 +45,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = {
static int dbx500_cpufreq_probe(struct platform_device *pdev)
{
int i = 0;
struct cpufreq_frequency_table *pos;
freq_table = dev_get_platdata(&pdev->dev);
if (!freq_table) {
......@@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev)
}
pr_info("dbx500-cpufreq: Available frequencies:\n");
while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
i++;
}
cpufreq_for_each_entry(pos, freq_table)
pr_info(" %d Mhz\n", pos->frequency / 1000);
return cpufreq_register_driver(&dbx500_cpufreq_driver);
}
......
......@@ -147,7 +147,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = &cpu_data(0);
unsigned int i;
struct cpufreq_frequency_table *pos;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
......@@ -159,10 +159,9 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
max_freq = elanfreq_get_cpu_frequency(0);
/* table init */
for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
cpufreq_for_each_entry(pos, elanfreq_table)
if (pos->frequency > max_freq)
pos->frequency = CPUFREQ_ENTRY_INVALID;
/* cpuinfo and default policy values */
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
......
......@@ -29,17 +29,16 @@ static unsigned int locking_frequency;
static int exynos_cpufreq_get_index(unsigned int freq)
{
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
int index;
struct cpufreq_frequency_table *pos;
for (index = 0;
freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
if (freq_table[index].frequency == freq)
cpufreq_for_each_entry(pos, freq_table)
if (pos->frequency == freq)
break;
if (freq_table[index].frequency == CPUFREQ_TABLE_END)
if (pos->frequency == CPUFREQ_TABLE_END)
return -EINVAL;
return index;
return pos - freq_table;
}
static int exynos_cpufreq_scale(unsigned int target_freq)
......
......@@ -114,25 +114,23 @@ static struct cpufreq_freqs freqs;
static int init_div_table(void)
{
struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table;
unsigned int tmp, clk_div, ema_div, freq, volt_id;
int i = 0;
struct dev_pm_opp *opp;
rcu_read_lock();
for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
cpufreq_for_each_entry(pos, freq_tbl) {
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
freq_tbl[i].frequency * 1000, true);
pos->frequency * 1000, true);
if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(dvfs_info->dev,
"failed to find valid OPP for %u KHZ\n",
freq_tbl[i].frequency);
pos->frequency);
return PTR_ERR(opp);
}
freq = freq_tbl[i].frequency / 1000; /* In MHZ */
freq = pos->frequency / 1000; /* In MHZ */
clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
<< P0_7_CPUCLKDEV_SHIFT;
clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
......@@ -157,7 +155,8 @@ static int init_div_table(void)
tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
| ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i);
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
(pos - freq_tbl));
}
rcu_read_unlock();
......@@ -166,8 +165,9 @@ static int init_div_table(void)
static void exynos_enable_dvfs(unsigned int cur_frequency)
{
unsigned int tmp, i, cpu;
unsigned int tmp, cpu;
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
struct cpufreq_frequency_table *pos;
/* Disable DVFS */
__raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
......@@ -182,15 +182,15 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
/* Set initial performance index */
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
if (freq_table[i].frequency == cur_frequency)
cpufreq_for_each_entry(pos, freq_table)
if (pos->frequency == cur_frequency)
break;
if (freq_table[i].frequency == CPUFREQ_TABLE_END) {
if (pos->frequency == CPUFREQ_TABLE_END) {
dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
/* Assign the highest frequency */
i = 0;
cur_frequency = freq_table[i].frequency;
pos = freq_table;
cur_frequency = pos->frequency;
}
dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
......@@ -199,7 +199,7 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
tmp |= (i << C0_3_PSTATE_NEW_SHIFT);
tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
}
......
......@@ -21,22 +21,19 @@
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
struct cpufreq_frequency_table *pos;
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
unsigned int i;
unsigned int freq;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) {
pr_debug("table entry %u is invalid, skipping\n", i);
cpufreq_for_each_valid_entry(pos, table) {
freq = pos->frequency;
continue;
}
if (!cpufreq_boost_enabled()
&& (table[i].flags & CPUFREQ_BOOST_FREQ))
&& (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
pr_debug("table entry %u: %u kHz\n", i, freq);
pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
if (freq < min_freq)
min_freq = freq;
if (freq > max_freq)
......@@ -57,7 +54,8 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
unsigned int next_larger = ~0, freq, i = 0;
struct cpufreq_frequency_table *pos;
unsigned int freq, next_larger = ~0;
bool found = false;
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
......@@ -65,9 +63,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
cpufreq_verify_within_cpu_limits(policy);
for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) {
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table) {
freq = pos->frequency;
if ((freq >= policy->min) && (freq <= policy->max)) {
found = true;
break;
......@@ -118,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
.driver_data = ~0,
.frequency = 0,
};
unsigned int i;
struct cpufreq_frequency_table *pos;
unsigned int freq, i = 0;
pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
target_freq, relation, policy->cpu);
......@@ -132,10 +131,10 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
break;
}
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table) {
freq = pos->frequency;
i = pos - table;
if ((freq < policy->min) || (freq > policy->max))
continue;
switch (relation) {
......@@ -184,8 +183,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
unsigned int freq)
{
struct cpufreq_frequency_table *table;
int i;
struct cpufreq_frequency_table *pos, *table;
table = cpufreq_frequency_get_table(policy->cpu);
if (unlikely(!table)) {
......@@ -193,10 +191,9 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
return -ENOENT;
}
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (table[i].frequency == freq)
return i;
}
cpufreq_for_each_valid_entry(pos, table)
if (pos->frequency == freq)
return pos - table;
return -EINVAL;
}
......@@ -208,16 +205,13 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
bool show_boost)
{
unsigned int i = 0;
ssize_t count = 0;
struct cpufreq_frequency_table *table = policy->freq_table;
struct cpufreq_frequency_table *pos, *table = policy->freq_table;
if (!table)
return -ENODEV;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
cpufreq_for_each_valid_entry(pos, table) {
/*
* show_boost = true and driver_data = BOOST freq
* display BOOST freqs
......@@ -229,10 +223,10 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
* show_boost = false and driver_data != BOOST freq
* display NON BOOST freqs
*/
if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ))
if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
count += sprintf(&buf[count], "%d ", table[i].frequency);
count += sprintf(&buf[count], "%d ", pos->frequency);
}
count += sprintf(&buf[count], "\n");
......
......@@ -530,6 +530,7 @@ static int longhaul_get_ranges(void)
static void longhaul_setup_voltagescaling(void)
{
struct cpufreq_frequency_table *freq_pos;
union msr_longhaul longhaul;
struct mV_pos minvid, maxvid, vid;
unsigned int j, speed, pos, kHz_step, numvscales;
......@@ -608,18 +609,16 @@ static void longhaul_setup_voltagescaling(void)
/* Calculate kHz for one voltage step */
kHz_step = (highest_speed - min_vid_speed) / numvscales;
j = 0;
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
speed = longhaul_table[j].frequency;
cpufreq_for_each_entry(freq_pos, longhaul_table) {
speed = freq_pos->frequency;
if (speed > min_vid_speed)
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
else
pos = minvid.pos;
longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8;
freq_pos->driver_data |= mV_vrm_table[pos] << 8;
vid = vrm_mV_table[mV_vrm_table[pos]];
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
speed, j, vid.mV);
j++;
speed, (int)(freq_pos - longhaul_table), vid.mV);
}
can_scale_voltage = 1;
......
......@@ -136,9 +136,10 @@ void restore_astate(int cpu)
static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
const u32 *max_freqp;
u32 max_freq;
int i, cur_astate;
int cur_astate;
struct resource res;
struct device_node *cpu, *dn;
int err = -ENODEV;
......@@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n");
/* initialize frequency table */
for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
pas_freqs[i].frequency =
get_astate_freq(pas_freqs[i].driver_data) * 100000;
pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
cpufreq_for_each_entry(pos, pas_freqs) {
pos->frequency = get_astate_freq(pos->driver_data) * 100000;
pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency);
}
cur_astate = get_cur_astate(policy->cpu);
......
......@@ -151,6 +151,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
unsigned int i, f;
unsigned khz;
......@@ -168,12 +169,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
}
}
if (param_max_multiplier) {
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
if (clock_ratio[i].driver_data == param_max_multiplier) {
cpufreq_for_each_entry(pos, clock_ratio)
if (pos->driver_data == param_max_multiplier) {
max_multiplier = param_max_multiplier;
goto have_max_multiplier;
}
}
printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
return -EINVAL;
}
......@@ -201,12 +201,12 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
param_busfreq = busfreq * 10;
/* table init */
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
f = clock_ratio[i].driver_data;
cpufreq_for_each_entry(pos, clock_ratio) {
f = pos->driver_data;
if (f > max_multiplier)
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
pos->frequency = CPUFREQ_ENTRY_INVALID;
else
clock_ratio[i].frequency = busfreq * f;
pos->frequency = busfreq * f;
}
/* cpuinfo and default policy values */
......
......@@ -67,9 +67,10 @@ static int set_pmode(unsigned int cpu, unsigned int slow_mode)
static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
const u32 *max_freqp;
u32 max_freq;
int i, cur_pmode;
int cur_pmode;
struct device_node *cpu;
cpu = of_get_cpu_node(policy->cpu, NULL);
......@@ -102,9 +103,9 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n");
/* initialize frequency table */
for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
cpufreq_for_each_entry(pos, cbe_freqs) {
pos->frequency = max_freq / pos->driver_data;
pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
}
/* if DEBUG is enabled set_pmode() measures the latency
......
......@@ -266,7 +266,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
{
int count, v, i, found;
struct cpufreq_frequency_table *freq;
struct cpufreq_frequency_table *pos;
struct s3c2416_dvfs *dvfs;
count = regulator_count_voltages(s3c_freq->vddarm);
......@@ -275,12 +275,11 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
return;
}
freq = s3c_freq->freq_table;
while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
continue;
if (!count)
goto out;
dvfs = &s3c2416_dvfs_table[freq->driver_data];
cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) {
dvfs = &s3c2416_dvfs_table[pos->driver_data];
found = 0;
/* Check only the min-voltage, more is always ok on S3C2416 */
......@@ -292,13 +291,12 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
if (!found) {
pr_debug("cpufreq: %dkHz unsupported by regulator\n",
freq->frequency);
freq->frequency = CPUFREQ_ENTRY_INVALID;
pos->frequency);
pos->frequency = CPUFREQ_ENTRY_INVALID;
}
freq++;
}
out:
/* Guessed */
s3c_freq->regulator_latency = 1 * 1000 * 1000;
}
......@@ -338,7 +336,7 @@ static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
struct cpufreq_frequency_table *freq;
struct cpufreq_frequency_table *pos;
struct clk *msysclk;
unsigned long rate;
int ret;
......@@ -427,31 +425,27 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
s3c_freq->regulator_latency = 0;
#endif
freq = s3c_freq->freq_table;
while (freq->frequency != CPUFREQ_TABLE_END) {
cpufreq_for_each_entry(pos, s3c_freq->freq_table) {
/* special handling for dvs mode */
if (freq->driver_data == 0) {
if (pos->driver_data == 0) {
if (!s3c_freq->hclk) {
pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
freq->frequency);
freq->frequency = CPUFREQ_ENTRY_INVALID;
pos->frequency);
pos->frequency = CPUFREQ_ENTRY_INVALID;
} else {
freq++;
continue;
}
}
/* Check for frequencies we can generate */
rate = clk_round_rate(s3c_freq->armdiv,
freq->frequency * 1000);
pos->frequency * 1000);
rate /= 1000;
if (rate != freq->frequency) {
if (rate != pos->frequency) {
pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
freq->frequency, rate);
freq->frequency = CPUFREQ_ENTRY_INVALID;
pos->frequency, rate);
pos->frequency = CPUFREQ_ENTRY_INVALID;
}
freq++;
}
/* Datasheet says PLL stabalisation time must be at least 300us,
......
......@@ -118,11 +118,10 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
pr_err("Unable to check supported voltages\n");
}
freq = s3c64xx_freq_table;
while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
continue;
if (!count)
goto out;
cpufreq_for_each_valid_entry(freq, s3c64xx_freq_table) {
dvfs = &s3c64xx_dvfs_table[freq->driver_data];
found = 0;
......@@ -137,10 +136,9 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
freq->frequency);
freq->frequency = CPUFREQ_ENTRY_INVALID;
}
freq++;
}
out:
/* Guess based on having to do an I2C/SPI write; in future we
* will be able to query the regulator performance here. */
regulator_latency = 1 * 1000 * 1000;
......@@ -179,8 +177,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
}
#endif
freq = s3c64xx_freq_table;
while (freq->frequency != CPUFREQ_TABLE_END) {
cpufreq_for_each_entry(freq, s3c64xx_freq_table) {
unsigned long r;
/* Check for frequencies we can generate */
......@@ -196,8 +193,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
* frequency is the maximum we can support. */
if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000)
freq->frequency = CPUFREQ_ENTRY_INVALID;
freq++;
}
/* Datasheet says PLL stabalisation time (if we were to use
......
......@@ -28,13 +28,13 @@ config EXTCON_ADC_JACK
Say Y here to enable extcon device driver based on ADC values.
config EXTCON_MAX14577
tristate "MAX14577 EXTCON Support"
tristate "MAX14577/77836 EXTCON Support"
depends on MFD_MAX14577
select IRQ_DOMAIN
select REGMAP_I2C
help
If you say yes here you get support for the MUIC device of
Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
detector and switch.
config EXTCON_MAX77693
......
/*
* extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
* extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2013,2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -24,7 +25,6 @@
#include <linux/mfd/max14577-private.h>
#include <linux/extcon.h>
#define DEV_NAME "max14577-muic"
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
enum max14577_muic_adc_debounce_time {
......@@ -40,6 +40,42 @@ enum max14577_muic_status {
MAX14577_MUIC_STATUS_END,
};
/**
* struct max14577_muic_irq
* @irq: the index of irq list of MUIC device.
* @name: the name of irq.
* @virq: the virtual irq to use irq domain
*/
struct max14577_muic_irq {
unsigned int irq;
const char *name;
unsigned int virq;
};
static struct max14577_muic_irq max14577_muic_irqs[] = {
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
};
static struct max14577_muic_irq max77836_muic_irqs[] = {
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
{ MAX77836_IRQ_INT1_ADC1K, "muic-ADC1K" },
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
{ MAX77836_IRQ_INT2_VIDRM, "muic-VIDRM" },
};
struct max14577_muic_info {
struct device *dev;
struct max14577 *max14577;
......@@ -48,6 +84,8 @@ struct max14577_muic_info {
int prev_chg_type;
u8 status[MAX14577_MUIC_STATUS_END];
struct max14577_muic_irq *muic_irqs;
unsigned int muic_irqs_num;
bool irq_adc;
bool irq_chg;
struct work_struct irq_work;
......@@ -74,29 +112,6 @@ enum max14577_muic_cable_group {
MAX14577_CABLE_GROUP_CHG,
};
/**
* struct max14577_muic_irq
* @irq: the index of irq list of MUIC device.
* @name: the name of irq.
* @virq: the virtual irq to use irq domain
*/
struct max14577_muic_irq {
unsigned int irq;
const char *name;
unsigned int virq;
};
static struct max14577_muic_irq muic_irqs[] = {
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
};
/* Define supported accessory type */
enum max14577_muic_acc_type {
MAX14577_MUIC_ADC_GROUND = 0x0,
......@@ -528,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work)
return;
}
static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
/*
* Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
* Returns 0 if irq_type does not match registered IRQ for this device type.
*/
static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
{
struct max14577_muic_info *info = data;
int i, irq_type = -1;
/*
* We may be called multiple times for different nested IRQ-s.
* Including changes in INT1_ADC and INT2_CGHTYP at once.
* However we only need to know whether it was ADC, charger
* or both interrupts so decode IRQ and turn on proper flags.
*/
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
if (irq == muic_irqs[i].virq)
irq_type = muic_irqs[i].irq;
switch (irq_type) {
case MAX14577_IRQ_INT1_ADC:
case MAX14577_IRQ_INT1_ADCLOW:
......@@ -550,7 +556,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
/* Handle all of accessory except for
type of charger accessory */
info->irq_adc = true;
break;
return 1;
case MAX14577_IRQ_INT2_CHGTYP:
case MAX14577_IRQ_INT2_CHGDETRUN:
case MAX14577_IRQ_INT2_DCDTMR:
......@@ -558,8 +564,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
case MAX14577_IRQ_INT2_VBVOLT:
/* Handle charger accessory */
info->irq_chg = true;
return 1;
default:
return 0;
}
}
/*
* Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
* Returns 0 if irq_type does not match registered IRQ for this device type.
*/
static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type)
{
/* First check common max14577 interrupts */
if (max14577_parse_irq(info, irq_type))
return 1;
switch (irq_type) {
case MAX77836_IRQ_INT1_ADC1K:
info->irq_adc = true;
return 1;
case MAX77836_IRQ_INT2_VIDRM:
/* Handle charger accessory */
info->irq_chg = true;
return 1;
default:
return 0;
}
}
static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
{
struct max14577_muic_info *info = data;
int i, irq_type = -1;
bool irq_parsed;
/*
* We may be called multiple times for different nested IRQ-s.
* Including changes in INT1_ADC and INT2_CGHTYP at once.
* However we only need to know whether it was ADC, charger
* or both interrupts so decode IRQ and turn on proper flags.
*/
for (i = 0; i < info->muic_irqs_num; i++)
if (irq == info->muic_irqs[i].virq)
irq_type = info->muic_irqs[i].irq;
switch (info->max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
irq_parsed = max77836_parse_irq(info, irq_type);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
irq_parsed = max14577_parse_irq(info, irq_type);
break;
}
if (!irq_parsed) {
dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
irq_type);
return IRQ_HANDLED;
......@@ -644,9 +704,20 @@ static int max14577_muic_probe(struct platform_device *pdev)
INIT_WORK(&info->irq_work, max14577_muic_irq_work);
switch (max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
info->muic_irqs = max77836_muic_irqs;
info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
info->muic_irqs = max14577_muic_irqs;
info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs);
}
/* Support irq domain for max14577 MUIC device */
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max14577_muic_irq *muic_irq = &muic_irqs[i];
for (i = 0; i < info->muic_irqs_num; i++) {
struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
unsigned int virq = 0;
virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
......@@ -673,7 +744,8 @@ static int max14577_muic_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
return -ENOMEM;
}
info->edev->name = DEV_NAME;
info->edev->name = dev_name(&pdev->dev);
info->edev->supported_cable = max14577_extcon_cable;
ret = extcon_dev_register(info->edev);
if (ret) {
......@@ -735,18 +807,26 @@ static int max14577_muic_remove(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id max14577_muic_id[] = {
{ "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },
{ "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },
{ }
};
MODULE_DEVICE_TABLE(platform, max14577_muic_id);
static struct platform_driver max14577_muic_driver = {
.driver = {
.name = DEV_NAME,
.name = "max14577-muic",
.owner = THIS_MODULE,
},
.probe = max14577_muic_probe,
.remove = max14577_muic_remove,
.id_table = max14577_muic_id,
};
module_platform_driver(max14577_muic_driver);
MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:extcon-max14577");
......@@ -23,7 +23,8 @@
enum { REG_RE, REG_FE, REG_IE };
#define CACHE_NR_REGS 3
#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8)
/* No variant has more than 24 GPIOs */
#define CACHE_NR_BANKS (24 / 8)
struct stmpe_gpio {
struct gpio_chip chip;
......@@ -31,8 +32,6 @@ struct stmpe_gpio {
struct device *dev;
struct mutex irq_lock;
struct irq_domain *domain;
int irq_base;
unsigned norequest_mask;
/* Caches of interrupt control registers for bus_lock */
......@@ -311,13 +310,8 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
struct device_node *np)
{
int base = 0;
if (!np)
base = stmpe_gpio->irq_base;
stmpe_gpio->domain = irq_domain_add_simple(np,
stmpe_gpio->chip.ngpio, base,
stmpe_gpio->chip.ngpio, 0,
&stmpe_gpio_irq_simple_ops, stmpe_gpio);
if (!stmpe_gpio->domain) {
dev_err(stmpe_gpio->dev, "failed to create irqdomain\n");
......@@ -354,7 +348,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
stmpe_gpio->chip.of_node = np;
#endif
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
stmpe_gpio->chip.base = -1;
if (pdata)
stmpe_gpio->norequest_mask = pdata->norequest_mask;
......@@ -362,9 +356,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
of_property_read_u32(np, "st,norequest-mask",
&stmpe_gpio->norequest_mask);
if (irq >= 0)
stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
else
if (irq < 0)
dev_info(&pdev->dev,
"device configured in no-irq mode; "
"irqs are not available\n");
......
......@@ -52,3 +52,13 @@ config MEMSTICK_REALTEK_PCI
To compile this driver as a module, choose M here: the module will
be called rtsx_pci_ms.
config MEMSTICK_REALTEK_USB
tristate "Realtek USB Memstick Card Interface Driver"
depends on MFD_RTSX_USB
help
Say Y here to include driver code to support Memstick card interface
of Realtek RTS5129/39 series USB card reader
To compile this driver as a module, choose M here: the module will
be called rts5139_ms.
......@@ -6,3 +6,4 @@ obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o
obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o
obj-$(CONFIG_MEMSTICK_R592) += r592.o
obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o
obj-$(CONFIG_MEMSTICK_REALTEK_USB) += rtsx_usb_ms.o
/* Realtek USB Memstick Card Interface driver
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Roger Tseng <rogerable@realtek.com>
*/
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/memstick.h>
#include <linux/kthread.h>
#include <linux/mfd/rtsx_usb.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <asm/unaligned.h>
struct rtsx_usb_ms {
struct platform_device *pdev;
struct rtsx_ucr *ucr;
struct memstick_host *msh;
struct memstick_request *req;
struct mutex host_mutex;
struct work_struct handle_req;
struct task_struct *detect_ms;
struct completion detect_ms_exit;
u8 ssc_depth;
unsigned int clock;
int power_mode;
unsigned char ifmode;
bool eject;
};
static inline struct device *ms_dev(struct rtsx_usb_ms *host)
{
return &(host->pdev->dev);
}
static inline void ms_clear_error(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
rtsx_usb_ep0_write_register(ucr, CARD_STOP,
MS_STOP | MS_CLR_ERR,
MS_STOP | MS_CLR_ERR);
rtsx_usb_clear_dma_err(ucr);
rtsx_usb_clear_fsm_err(ucr);
}
#ifdef DEBUG
static void ms_print_debug_regs(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
u16 i;
u8 *ptr;
/* Print MS host internal registers */
rtsx_usb_init_cmd(ucr);
/* MS_CFG to MS_INT_REG */
for (i = 0xFD40; i <= 0xFD44; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0);
/* CARD_SHARE_MODE to CARD_GPIO */
for (i = 0xFD51; i <= 0xFD56; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0);
/* CARD_PULL_CTLx */
for (i = 0xFD60; i <= 0xFD65; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0);
/* CARD_DATA_SOURCE, CARD_SELECT, CARD_CLK_EN, CARD_PWR_CTL */
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_DATA_SOURCE, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_SELECT, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_CLK_EN, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_PWR_CTL, 0, 0);
rtsx_usb_send_cmd(ucr, MODE_CR, 100);
rtsx_usb_get_rsp(ucr, 21, 100);
ptr = ucr->rsp_buf;
for (i = 0xFD40; i <= 0xFD44; i++)
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
for (i = 0xFD51; i <= 0xFD56; i++)
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
for (i = 0xFD60; i <= 0xFD65; i++)
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_DATA_SOURCE, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_SELECT, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_CLK_EN, *(ptr++));
dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_PWR_CTL, *(ptr++));
}
#else
static void ms_print_debug_regs(struct rtsx_usb_ms *host)
{
}
#endif
static int ms_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_power_on(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(ms_dev(host), "%s\n", __func__);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE,
CARD_SHARE_MASK, CARD_SHARE_MS);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN,
MS_CLK_EN, MS_CLK_EN);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err < 0)
return err;
if (CHECK_PKG(ucr, LQFP48))
err = ms_pull_ctl_enable_lqfp48(ucr);
else
err = ms_pull_ctl_enable_qfn24(ucr);
if (err < 0)
return err;
err = rtsx_usb_write_register(ucr, CARD_PWR_CTL,
POWER_MASK, PARTIAL_POWER_ON);
if (err)
return err;
usleep_range(800, 1000);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
POWER_MASK, POWER_ON);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE,
MS_OUTPUT_EN, MS_OUTPUT_EN);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int ms_power_off(struct rtsx_usb_ms *host)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(ms_dev(host), "%s\n", __func__);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err < 0)
return err;
if (CHECK_PKG(ucr, LQFP48))
return ms_pull_ctl_disable_lqfp48(ucr);
return ms_pull_ctl_disable_qfn24(ucr);
}
static int ms_transfer_data(struct rtsx_usb_ms *host, unsigned char data_dir,
u8 tpc, u8 cfg, struct scatterlist *sg)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
unsigned int length = sg->length;
u16 sec_cnt = (u16)(length / 512);
u8 trans_mode, dma_dir, flag;
unsigned int pipe;
struct memstick_dev *card = host->msh->card;
dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n",
__func__, tpc, (data_dir == READ) ? "READ" : "WRITE",
length);
if (data_dir == READ) {
flag = MODE_CDIR;
dma_dir = DMA_DIR_FROM_CARD;
if (card->id.type != MEMSTICK_TYPE_PRO)
trans_mode = MS_TM_NORMAL_READ;
else
trans_mode = MS_TM_AUTO_READ;
pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN);
} else {
flag = MODE_CDOR;
dma_dir = DMA_DIR_TO_CARD;
if (card->id.type != MEMSTICK_TYPE_PRO)
trans_mode = MS_TM_NORMAL_WRITE;
else
trans_mode = MS_TM_AUTO_WRITE;
pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT);
}
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
if (card->id.type == MEMSTICK_TYPE_PRO) {
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_H,
0xFF, (u8)(sec_cnt >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_L,
0xFF, (u8)sec_cnt);
}
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3,
0xFF, (u8)(length >> 24));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2,
0xFF, (u8)(length >> 16));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1,
0xFF, (u8)(length >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0, 0xFF,
(u8)length);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, RING_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER,
0xFF, MS_TRANSFER_START | trans_mode);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER,
MS_TRANSFER_END, MS_TRANSFER_END);
err = rtsx_usb_send_cmd(ucr, flag | STAGE_MS_STATUS, 100);
if (err)
return err;
err = rtsx_usb_transfer_data(ucr, pipe, sg, length,
1, NULL, 10000);
if (err)
goto err_out;
err = rtsx_usb_get_rsp(ucr, 3, 15000);
if (err)
goto err_out;
if (ucr->rsp_buf[0] & MS_TRANSFER_ERR ||
ucr->rsp_buf[1] & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
err = -EIO;
goto err_out;
}
return 0;
err_out:
ms_clear_error(host);
return err;
}
static int ms_write_bytes(struct rtsx_usb_ms *host, u8 tpc,
u8 cfg, u8 cnt, u8 *data, u8 *int_reg)
{
struct rtsx_ucr *ucr = host->ucr;
int err, i;
dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc);
rtsx_usb_init_cmd(ucr);
for (i = 0; i < cnt; i++)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
PPBUF_BASE2 + i, 0xFF, data[i]);
if (cnt % 2)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
PPBUF_BASE2 + i, 0xFF, 0xFF);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER,
0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER,
MS_TRANSFER_END, MS_TRANSFER_END);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (err)
return err;
err = rtsx_usb_get_rsp(ucr, 2, 5000);
if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) {
u8 val;
rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val);
dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val);
if (int_reg)
*int_reg = val & 0x0F;
ms_print_debug_regs(host);
ms_clear_error(host);
if (!(tpc & 0x08)) {
if (val & MS_CRC16_ERR)
return -EIO;
} else {
if (!(val & 0x80)) {
if (val & (MS_INT_ERR | MS_INT_CMDNK))
return -EIO;
}
}
return -ETIMEDOUT;
}
if (int_reg)
*int_reg = ucr->rsp_buf[1] & 0x0F;
return 0;
}
static int ms_read_bytes(struct rtsx_usb_ms *host, u8 tpc,
u8 cfg, u8 cnt, u8 *data, u8 *int_reg)
{
struct rtsx_ucr *ucr = host->ucr;
int err, i;
u8 *ptr;
dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER,
0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER,
MS_TRANSFER_END, MS_TRANSFER_END);
for (i = 0; i < cnt - 1; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
if (cnt % 2)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0);
else
rtsx_usb_add_cmd(ucr, READ_REG_CMD,
PPBUF_BASE2 + cnt - 1, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (err)
return err;
err = rtsx_usb_get_rsp(ucr, cnt + 2, 5000);
if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) {
u8 val;
rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val);
dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val);
if (int_reg && (host->ifmode != MEMSTICK_SERIAL))
*int_reg = val & 0x0F;
ms_print_debug_regs(host);
ms_clear_error(host);
if (!(tpc & 0x08)) {
if (val & MS_CRC16_ERR)
return -EIO;
} else {
if (!(val & 0x80)) {
if (val & (MS_INT_ERR | MS_INT_CMDNK))
return -EIO;
}
}
return -ETIMEDOUT;
}
ptr = ucr->rsp_buf + 1;
for (i = 0; i < cnt; i++)
data[i] = *ptr++;
if (int_reg && (host->ifmode != MEMSTICK_SERIAL))
*int_reg = *ptr & 0x0F;
return 0;
}
static int rtsx_usb_ms_issue_cmd(struct rtsx_usb_ms *host)
{
struct memstick_request *req = host->req;
int err = 0;
u8 cfg = 0, int_reg;
dev_dbg(ms_dev(host), "%s\n", __func__);
if (req->need_card_int) {
if (host->ifmode != MEMSTICK_SERIAL)
cfg = WAIT_INT;
}
if (req->long_data) {
err = ms_transfer_data(host, req->data_dir,
req->tpc, cfg, &(req->sg));
} else {
if (req->data_dir == READ)
err = ms_read_bytes(host, req->tpc, cfg,
req->data_len, req->data, &int_reg);
else
err = ms_write_bytes(host, req->tpc, cfg,
req->data_len, req->data, &int_reg);
}
if (err < 0)
return err;
if (req->need_card_int) {
if (host->ifmode == MEMSTICK_SERIAL) {
err = ms_read_bytes(host, MS_TPC_GET_INT,
NO_WAIT_INT, 1, &req->int_reg, NULL);
if (err < 0)
return err;
} else {
if (int_reg & MS_INT_CMDNK)
req->int_reg |= MEMSTICK_INT_CMDNAK;
if (int_reg & MS_INT_BREQ)
req->int_reg |= MEMSTICK_INT_BREQ;
if (int_reg & MS_INT_ERR)
req->int_reg |= MEMSTICK_INT_ERR;
if (int_reg & MS_INT_CED)
req->int_reg |= MEMSTICK_INT_CED;
}
dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", req->int_reg);
}
return 0;
}
static void rtsx_usb_ms_handle_req(struct work_struct *work)
{
struct rtsx_usb_ms *host = container_of(work,
struct rtsx_usb_ms, handle_req);
struct rtsx_ucr *ucr = host->ucr;
struct memstick_host *msh = host->msh;
int rc;
if (!host->req) {
do {
rc = memstick_next_req(msh, &host->req);
dev_dbg(ms_dev(host), "next req %d\n", rc);
if (!rc) {
mutex_lock(&ucr->dev_mutex);
if (rtsx_usb_card_exclusive_check(ucr,
RTSX_USB_MS_CARD))
host->req->error = -EIO;
else
host->req->error =
rtsx_usb_ms_issue_cmd(host);
mutex_unlock(&ucr->dev_mutex);
dev_dbg(ms_dev(host), "req result %d\n",
host->req->error);
}
} while (!rc);
}
}
static void rtsx_usb_ms_request(struct memstick_host *msh)
{
struct rtsx_usb_ms *host = memstick_priv(msh);
dev_dbg(ms_dev(host), "--> %s\n", __func__);
if (!host->eject)
schedule_work(&host->handle_req);
}
static int rtsx_usb_ms_set_param(struct memstick_host *msh,
enum memstick_param param, int value)
{
struct rtsx_usb_ms *host = memstick_priv(msh);
struct rtsx_ucr *ucr = host->ucr;
unsigned int clock = 0;
u8 ssc_depth = 0;
int err;
dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
__func__, param, value);
mutex_lock(&ucr->dev_mutex);
err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD);
if (err)
goto out;
switch (param) {
case MEMSTICK_POWER:
if (value == host->power_mode)
break;
if (value == MEMSTICK_POWER_ON) {
pm_runtime_get_sync(ms_dev(host));
err = ms_power_on(host);
} else if (value == MEMSTICK_POWER_OFF) {
err = ms_power_off(host);
if (host->msh->card)
pm_runtime_put_noidle(ms_dev(host));
else
pm_runtime_put(ms_dev(host));
} else
err = -EINVAL;
if (!err)
host->power_mode = value;
break;
case MEMSTICK_INTERFACE:
if (value == MEMSTICK_SERIAL) {
clock = 19000000;
ssc_depth = SSC_DEPTH_512K;
err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A,
MS_BUS_WIDTH_1 | PUSH_TIME_DEFAULT);
if (err < 0)
break;
} else if (value == MEMSTICK_PAR4) {
clock = 39000000;
ssc_depth = SSC_DEPTH_1M;
err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A,
MS_BUS_WIDTH_4 | PUSH_TIME_ODD |
MS_NO_CHECK_INT);
if (err < 0)
break;
} else {
err = -EINVAL;
break;
}
err = rtsx_usb_switch_clock(ucr, clock,
ssc_depth, false, true, false);
if (err < 0) {
dev_dbg(ms_dev(host), "switch clock failed\n");
break;
}
host->ssc_depth = ssc_depth;
host->clock = clock;
host->ifmode = value;
break;
default:
err = -EINVAL;
break;
}
out:
mutex_unlock(&ucr->dev_mutex);
/* power-on delay */
if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON)
usleep_range(10000, 12000);
dev_dbg(ms_dev(host), "%s: return = %d\n", __func__, err);
return err;
}
#ifdef CONFIG_PM_SLEEP
static int rtsx_usb_ms_suspend(struct device *dev)
{
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
struct memstick_host *msh = host->msh;
dev_dbg(ms_dev(host), "--> %s\n", __func__);
memstick_suspend_host(msh);
return 0;
}
static int rtsx_usb_ms_resume(struct device *dev)
{
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
struct memstick_host *msh = host->msh;
dev_dbg(ms_dev(host), "--> %s\n", __func__);
memstick_resume_host(msh);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
/*
* Thread function of ms card slot detection. The thread starts right after
* successful host addition. It stops while the driver removal function sets
* host->eject true.
*/
static int rtsx_usb_detect_ms_card(void *__host)
{
struct rtsx_usb_ms *host = (struct rtsx_usb_ms *)__host;
struct rtsx_ucr *ucr = host->ucr;
u8 val = 0;
int err;
for (;;) {
mutex_lock(&ucr->dev_mutex);
/* Check pending MS card changes */
err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val);
if (err) {
mutex_unlock(&ucr->dev_mutex);
goto poll_again;
}
/* Clear the pending */
rtsx_usb_write_register(ucr, CARD_INT_PEND,
XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
mutex_unlock(&ucr->dev_mutex);
if (val & MS_INT) {
dev_dbg(ms_dev(host), "MS slot change detected\n");
memstick_detect_change(host->msh);
}
poll_again:
if (host->eject)
break;
msleep(1000);
}
complete(&host->detect_ms_exit);
return 0;
}
static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
{
struct memstick_host *msh;
struct rtsx_usb_ms *host;
struct rtsx_ucr *ucr;
int err;
ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
if (!ucr)
return -ENXIO;
dev_dbg(&(pdev->dev),
"Realtek USB Memstick controller found\n");
msh = memstick_alloc_host(sizeof(*host), &pdev->dev);
if (!msh)
return -ENOMEM;
host = memstick_priv(msh);
host->ucr = ucr;
host->msh = msh;
host->pdev = pdev;
host->power_mode = MEMSTICK_POWER_OFF;
platform_set_drvdata(pdev, host);
mutex_init(&host->host_mutex);
INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req);
init_completion(&host->detect_ms_exit);
host->detect_ms = kthread_create(rtsx_usb_detect_ms_card, host,
"rtsx_usb_ms_%d", pdev->id);
if (IS_ERR(host->detect_ms)) {
dev_dbg(&(pdev->dev),
"Unable to create polling thread.\n");
err = PTR_ERR(host->detect_ms);
goto err_out;
}
msh->request = rtsx_usb_ms_request;
msh->set_param = rtsx_usb_ms_set_param;
msh->caps = MEMSTICK_CAP_PAR4;
pm_runtime_enable(&pdev->dev);
err = memstick_add_host(msh);
if (err)
goto err_out;
wake_up_process(host->detect_ms);
return 0;
err_out:
memstick_free_host(msh);
return err;
}
static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
{
struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
struct memstick_host *msh;
int err;
msh = host->msh;
host->eject = true;
cancel_work_sync(&host->handle_req);
mutex_lock(&host->host_mutex);
if (host->req) {
dev_dbg(&(pdev->dev),
"%s: Controller removed during transfer\n",
dev_name(&msh->dev));
host->req->error = -ENOMEDIUM;
do {
err = memstick_next_req(msh, &host->req);
if (!err)
host->req->error = -ENOMEDIUM;
} while (!err);
}
mutex_unlock(&host->host_mutex);
wait_for_completion(&host->detect_ms_exit);
memstick_remove_host(msh);
memstick_free_host(msh);
/* Balance possible unbalanced usage count
* e.g. unconditional module removal
*/
if (pm_runtime_active(ms_dev(host)))
pm_runtime_put(ms_dev(host));
pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
dev_dbg(&(pdev->dev),
": Realtek USB Memstick controller has been removed\n");
return 0;
}
static SIMPLE_DEV_PM_OPS(rtsx_usb_ms_pm_ops,
rtsx_usb_ms_suspend, rtsx_usb_ms_resume);
static struct platform_device_id rtsx_usb_ms_ids[] = {
{
.name = "rtsx_usb_ms",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids);
static struct platform_driver rtsx_usb_ms_driver = {
.probe = rtsx_usb_ms_drv_probe,
.remove = rtsx_usb_ms_drv_remove,
.id_table = rtsx_usb_ms_ids,
.driver = {
.owner = THIS_MODULE,
.name = "rtsx_usb_ms",
.pm = &rtsx_usb_ms_pm_ops,
},
};
module_platform_driver(rtsx_usb_ms_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
MODULE_DESCRIPTION("Realtek USB Memstick Card Host Driver");
......@@ -331,15 +331,15 @@ config MFD_88PM860X
battery-charger under the corresponding menus.
config MFD_MAX14577
bool "Maxim Semiconductor MAX14577 MUIC + Charger Support"
bool "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support"
depends on I2C=y
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
select IRQ_DOMAIN
help
Say yes here to add support for Maxim Semiconductor MAX14577.
This is a Micro-USB IC with Charger controls on chip.
Say yes here to add support for Maxim Semiconductor MAX14577 and
MAX77836 Micro-USB ICs with battery charger.
This driver provides common support for accessing the device;
additional drivers must be enabled in order to use the functionality
of the device.
......@@ -675,6 +675,7 @@ config MFD_DB8500_PRCMU
config MFD_STMPE
bool "STMicroelectronics STMPE"
depends on (I2C=y || SPI_MASTER=y)
depends on OF
select MFD_CORE
help
Support for the STMPE family of I/O Expanders from
......
......@@ -508,19 +508,31 @@ int arizona_of_get_type(struct device *dev)
}
EXPORT_SYMBOL_GPL(arizona_of_get_type);
int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
bool mandatory)
{
int gpio;
gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
if (gpio < 0) {
if (mandatory)
dev_err(arizona->dev,
"Mandatory DT gpio %s missing/malformed: %d\n",
prop, gpio);
gpio = 0;
}
return gpio;
}
EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
static int arizona_of_get_core_pdata(struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
int ret, i;
arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
"wlf,reset", 0);
if (arizona->pdata.reset < 0)
arizona->pdata.reset = 0;
arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node,
"wlf,ldoena", 0);
if (arizona->pdata.ldoena < 0)
arizona->pdata.ldoena = 0;
pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
ret = of_property_read_u32_array(arizona->dev->of_node,
"wlf,gpio-defaults",
......@@ -652,6 +664,9 @@ int arizona_dev_init(struct arizona *arizona)
return -EINVAL;
}
/* Mark DCVDD as external, LDO1 driver will clear if internal */
arizona->external_dcvdd = true;
ret = mfd_add_devices(arizona->dev, -1, early_devs,
ARRAY_SIZE(early_devs), NULL, 0, NULL);
if (ret != 0) {
......@@ -851,14 +866,6 @@ int arizona_dev_init(struct arizona *arizona)
arizona->pdata.gpio_defaults[i]);
}
/*
* LDO1 can only be used to supply DCVDD so if it has no
* consumers then DCVDD is supplied externally.
*/
if (arizona->pdata.ldo1 &&
arizona->pdata.ldo1->num_consumer_supplies == 0)
arizona->external_dcvdd = true;
pm_runtime_set_autosuspend_delay(arizona->dev, 100);
pm_runtime_use_autosuspend(arizona->dev);
pm_runtime_enable(arizona->dev);
......
......@@ -1734,18 +1734,17 @@ static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
static long round_armss_rate(unsigned long rate)
{
struct cpufreq_frequency_table *pos;
long freq = 0;
int i = 0;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
freq = db8500_cpufreq_table[i].frequency;
cpufreq_for_each_entry(pos, db8500_cpufreq_table) {
freq = pos->frequency;
if (freq == rate)
break;
i++;
}
/* Return the last valid value, even if a match was not found. */
......@@ -1886,23 +1885,21 @@ static void set_clock_rate(u8 clock, unsigned long rate)
static int set_armss_rate(unsigned long rate)
{
int i = 0;
struct cpufreq_frequency_table *pos;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
if (db8500_cpufreq_table[i].frequency == rate)
cpufreq_for_each_entry(pos, db8500_cpufreq_table)
if (pos->frequency == rate)
break;
i++;
}
if (db8500_cpufreq_table[i].frequency != rate)
if (pos->frequency != rate)
return -EINVAL;
/* Set the new arm opp. */
return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].driver_data);
return db8500_prcmu_set_arm_opp(pos->driver_data);
}
static int set_plldsi_rate(unsigned long rate)
......
/*
* max14577.c - mfd core driver for the Maxim 14577
* max14577.c - mfd core driver for the Maxim 14577/77836
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
......@@ -21,6 +21,7 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max14577.h>
#include <linux/mfd/max14577-private.h>
......@@ -37,7 +38,38 @@ static struct mfd_cell max14577_devs[] = {
{ .name = "max14577-charger", },
};
static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
static struct mfd_cell max77836_devs[] = {
{
.name = "max77836-muic",
.of_compatible = "maxim,max77836-muic",
},
{
.name = "max77836-regulator",
.of_compatible = "maxim,max77836-regulator",
},
{
.name = "max77836-charger",
.of_compatible = "maxim,max77836-charger",
},
{
.name = "max77836-battery",
.of_compatible = "maxim,max77836-battery",
},
};
static struct of_device_id max14577_dt_match[] = {
{
.compatible = "maxim,max14577",
.data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
},
{
.compatible = "maxim,max77836",
.data = (void *)MAXIM_DEVICE_TYPE_MAX77836,
},
{},
};
static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3:
......@@ -48,49 +80,221 @@ static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
return false;
}
static const struct regmap_config max14577_regmap_config = {
static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg)
{
/* Any max14577 volatile registers are also max77836 volatile. */
if (max14577_muic_volatile_reg(dev, reg))
return true;
switch (reg) {
case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB:
case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB:
case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L:
case MAX77836_PMIC_REG_INTSRC:
case MAX77836_PMIC_REG_TOPSYS_INT:
case MAX77836_PMIC_REG_TOPSYS_STAT:
return true;
default:
break;
}
return false;
}
static const struct regmap_config max14577_muic_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = max14577_volatile_reg,
.volatile_reg = max14577_muic_volatile_reg,
.max_register = MAX14577_REG_END,
};
static const struct regmap_config max77836_pmic_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = max77836_muic_volatile_reg,
.max_register = MAX77836_PMIC_REG_END,
};
static const struct regmap_irq max14577_irqs[] = {
/* INT1 interrupts */
{ .reg_offset = 0, .mask = INT1_ADC_MASK, },
{ .reg_offset = 0, .mask = INT1_ADCLOW_MASK, },
{ .reg_offset = 0, .mask = INT1_ADCERR_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
/* INT2 interrupts */
{ .reg_offset = 1, .mask = INT2_CHGTYP_MASK, },
{ .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, },
{ .reg_offset = 1, .mask = INT2_DCDTMR_MASK, },
{ .reg_offset = 1, .mask = INT2_DBCHG_MASK, },
{ .reg_offset = 1, .mask = INT2_VBVOLT_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
/* INT3 interrupts */
{ .reg_offset = 2, .mask = INT3_EOC_MASK, },
{ .reg_offset = 2, .mask = INT3_CGMBC_MASK, },
{ .reg_offset = 2, .mask = INT3_OVP_MASK, },
{ .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
};
static const struct regmap_irq_chip max14577_irq_chip = {
.name = "max14577",
.status_base = MAX14577_REG_INT1,
.mask_base = MAX14577_REG_INTMASK1,
.mask_invert = 1,
.mask_invert = true,
.num_regs = 3,
.irqs = max14577_irqs,
.num_irqs = ARRAY_SIZE(max14577_irqs),
};
static const struct regmap_irq max77836_muic_irqs[] = {
/* INT1 interrupts */
{ .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
{ .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, },
/* INT2 interrupts */
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
{ .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
{ .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, },
/* INT3 interrupts */
{ .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
{ .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
};
static const struct regmap_irq_chip max77836_muic_irq_chip = {
.name = "max77836-muic",
.status_base = MAX14577_REG_INT1,
.mask_base = MAX14577_REG_INTMASK1,
.mask_invert = true,
.num_regs = 3,
.irqs = max77836_muic_irqs,
.num_irqs = ARRAY_SIZE(max77836_muic_irqs),
};
static const struct regmap_irq max77836_pmic_irqs[] = {
{ .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, },
{ .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, },
};
static const struct regmap_irq_chip max77836_pmic_irq_chip = {
.name = "max77836-pmic",
.status_base = MAX77836_PMIC_REG_TOPSYS_INT,
.mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK,
.mask_invert = false,
.num_regs = 1,
.irqs = max77836_pmic_irqs,
.num_irqs = ARRAY_SIZE(max77836_pmic_irqs),
};
static void max14577_print_dev_type(struct max14577 *max14577)
{
u8 reg_data, vendor_id, device_id;
int ret;
ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
&reg_data);
if (ret) {
dev_err(max14577->dev,
"Failed to read DEVICEID register: %d\n", ret);
return;
}
vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
DEVID_VENDORID_SHIFT);
device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
DEVID_DEVICEID_SHIFT);
dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n",
max14577->dev_type, device_id, vendor_id);
}
/*
* Max77836 specific initialization code for driver probe.
* Adds new I2C dummy device, regmap and regmap IRQ chip.
* Unmasks Interrupt Source register.
*
* On success returns 0.
* On failure returns errno and reverts any changes done so far (e.g. remove
* I2C dummy device), except masking the INT SRC register.
*/
static int max77836_init(struct max14577 *max14577)
{
int ret;
u8 intsrc_mask;
max14577->i2c_pmic = i2c_new_dummy(max14577->i2c->adapter,
I2C_ADDR_PMIC);
if (!max14577->i2c_pmic) {
dev_err(max14577->dev, "Failed to register PMIC I2C device\n");
return -ENODEV;
}
i2c_set_clientdata(max14577->i2c_pmic, max14577);
max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic,
&max77836_pmic_regmap_config);
if (IS_ERR(max14577->regmap_pmic)) {
ret = PTR_ERR(max14577->regmap_pmic);
dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n",
ret);
goto err;
}
/* Un-mask MAX77836 Interrupt Source register */
ret = max14577_read_reg(max14577->regmap_pmic,
MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask);
if (ret < 0) {
dev_err(max14577->dev, "Failed to read PMIC register\n");
goto err;
}
intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK);
intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK);
ret = max14577_write_reg(max14577->regmap_pmic,
MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask);
if (ret < 0) {
dev_err(max14577->dev, "Failed to write PMIC register\n");
goto err;
}
ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED,
0, &max77836_pmic_irq_chip,
&max14577->irq_data_pmic);
if (ret != 0) {
dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n",
max14577->irq, ret);
goto err;
}
return 0;
err:
i2c_unregister_device(max14577->i2c_pmic);
return ret;
}
/*
* Max77836 specific de-initialization code for driver remove.
*/
static void max77836_remove(struct max14577 *max14577)
{
regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic);
i2c_unregister_device(max14577->i2c_pmic);
}
static int max14577_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max14577 *max14577;
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct device_node *np = i2c->dev.of_node;
u8 reg_data;
int ret = 0;
const struct regmap_irq_chip *irq_chip;
struct mfd_cell *mfd_devs;
unsigned int mfd_devs_size;
int irq_flags;
if (np) {
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
......@@ -113,7 +317,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
max14577->i2c = i2c;
max14577->irq = i2c->irq;
max14577->regmap = devm_regmap_init_i2c(i2c, &max14577_regmap_config);
max14577->regmap = devm_regmap_init_i2c(i2c,
&max14577_muic_regmap_config);
if (IS_ERR(max14577->regmap)) {
ret = PTR_ERR(max14577->regmap);
dev_err(max14577->dev, "Failed to allocate register map: %d\n",
......@@ -121,23 +326,36 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
&reg_data);
if (ret) {
dev_err(max14577->dev, "Device not found on this channel: %d\n",
ret);
return ret;
if (np) {
const struct of_device_id *of_id;
of_id = of_match_device(max14577_dt_match, &i2c->dev);
if (of_id)
max14577->dev_type = (unsigned int)of_id->data;
} else {
max14577->dev_type = id->driver_data;
}
max14577_print_dev_type(max14577);
switch (max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
irq_chip = &max77836_muic_irq_chip;
mfd_devs = max77836_devs;
mfd_devs_size = ARRAY_SIZE(max77836_devs);
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
irq_chip = &max14577_irq_chip;
mfd_devs = max14577_devs;
mfd_devs_size = ARRAY_SIZE(max14577_devs);
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
break;
}
max14577->vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
DEVID_VENDORID_SHIFT);
max14577->device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
DEVID_DEVICEID_SHIFT);
dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n",
max14577->device_id, max14577->vendor_id);
ret = regmap_add_irq_chip(max14577->regmap, max14577->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
&max14577_irq_chip,
irq_flags, 0, irq_chip,
&max14577->irq_data);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
......@@ -145,8 +363,15 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = mfd_add_devices(max14577->dev, -1, max14577_devs,
ARRAY_SIZE(max14577_devs), NULL, 0,
/* Max77836 specific initialization code (additional regmap) */
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) {
ret = max77836_init(max14577);
if (ret < 0)
goto err_max77836;
}
ret = mfd_add_devices(max14577->dev, -1, mfd_devs,
mfd_devs_size, NULL, 0,
regmap_irq_get_domain(max14577->irq_data));
if (ret < 0)
goto err_mfd;
......@@ -156,6 +381,9 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return 0;
err_mfd:
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
max77836_remove(max14577);
err_max77836:
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
return ret;
......@@ -167,12 +395,15 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(max14577->dev);
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
max77836_remove(max14577);
return 0;
}
static const struct i2c_device_id max14577_i2c_id[] = {
{ "max14577", 0 },
{ "max14577", MAXIM_DEVICE_TYPE_MAX14577, },
{ "max77836", MAXIM_DEVICE_TYPE_MAX77836, },
{ }
};
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
......@@ -215,11 +446,6 @@ static int max14577_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
static struct of_device_id max14577_dt_match[] = {
{ .compatible = "maxim,max14577", },
{},
};
static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume);
static struct i2c_driver max14577_i2c_driver = {
......@@ -236,6 +462,9 @@ static struct i2c_driver max14577_i2c_driver = {
static int __init max14577_i2c_init(void)
{
BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM);
BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM);
return i2c_add_driver(&max14577_i2c_driver);
}
subsys_initcall(max14577_i2c_init);
......@@ -247,5 +476,5 @@ static void __exit max14577_i2c_exit(void)
module_exit(max14577_i2c_exit);
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver");
MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
MODULE_LICENSE("GPL");
......@@ -673,9 +673,13 @@ int mc13xxx_common_init(struct device *dev)
if (mc13xxx->flags & MC13XXX_USE_ADC)
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
if (mc13xxx->flags & MC13XXX_USE_CODEC)
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
pdata->codec, sizeof(*pdata->codec));
if (mc13xxx->flags & MC13XXX_USE_CODEC) {
if (pdata)
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
pdata->codec, sizeof(*pdata->codec));
else
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
}
if (mc13xxx->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
......
......@@ -67,7 +67,7 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
add_timer(&ucr->sg_timer);
usb_sg_wait(&ucr->current_sg);
del_timer(&ucr->sg_timer);
del_timer_sync(&ucr->sg_timer);
if (act_len)
*act_len = ucr->current_sg.bytes;
......@@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf,
if (ret)
goto out_init_fail;
/* initialize USB SG transfer timer */
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
if (ret)
goto out_init_fail;
/* initialize USB SG transfer timer */
init_timer(&ucr->sg_timer);
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
#ifdef CONFIG_PM
intf->needs_remote_wakeup = 1;
usb_enable_autosuspend(usb_dev);
......@@ -687,9 +687,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n",
__func__, message.event);
/*
* Call to make sure LED is off during suspend to save more power.
* It is NOT a permanent state and could be turned on anytime later.
* Thus no need to call turn_on when resunming.
*/
mutex_lock(&ucr->dev_mutex);
rtsx_usb_turn_off_led(ucr);
mutex_unlock(&ucr->dev_mutex);
return 0;
}
......
......@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/of_device.h>
#include "stmpe.h"
static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
......@@ -52,15 +53,41 @@ static struct stmpe_client_info i2c_ci = {
.write_block = i2c_block_write,
};
static const struct of_device_id stmpe_of_match[] = {
{ .compatible = "st,stmpe610", .data = (void *)STMPE610, },
{ .compatible = "st,stmpe801", .data = (void *)STMPE801, },
{ .compatible = "st,stmpe811", .data = (void *)STMPE811, },
{ .compatible = "st,stmpe1601", .data = (void *)STMPE1601, },
{ .compatible = "st,stmpe1801", .data = (void *)STMPE1801, },
{ .compatible = "st,stmpe2401", .data = (void *)STMPE2401, },
{ .compatible = "st,stmpe2403", .data = (void *)STMPE2403, },
{},
};
MODULE_DEVICE_TABLE(of, stmpe_of_match);
static int
stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
int partnum;
const struct of_device_id *of_id;
i2c_ci.data = (void *)id;
i2c_ci.irq = i2c->irq;
i2c_ci.client = i2c;
i2c_ci.dev = &i2c->dev;
return stmpe_probe(&i2c_ci, id->driver_data);
of_id = of_match_device(stmpe_of_match, &i2c->dev);
if (!of_id) {
/*
* This happens when the I2C ID matches the node name
* but no real compatible string has been given.
*/
dev_info(&i2c->dev, "matching on node name, compatible is preferred\n");
partnum = id->driver_data;
} else
partnum = (int)of_id->data;
return stmpe_probe(&i2c_ci, partnum);
}
static int stmpe_i2c_remove(struct i2c_client *i2c)
......@@ -89,6 +116,7 @@ static struct i2c_driver stmpe_i2c_driver = {
#ifdef CONFIG_PM
.pm = &stmpe_dev_pm_ops,
#endif
.of_match_table = stmpe_of_match,
},
.probe = stmpe_i2c_probe,
.remove = stmpe_i2c_remove,
......
......@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/mfd/core.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include "stmpe.h"
static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
......@@ -605,9 +606,18 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
if (blocks & STMPE_BLOCK_GPIO)
mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
else
mask &= ~STMPE1601_SYS_CTRL_ENABLE_GPIO;
if (blocks & STMPE_BLOCK_KEYPAD)
mask |= STMPE1601_SYS_CTRL_ENABLE_KPC;
else
mask &= ~STMPE1601_SYS_CTRL_ENABLE_KPC;
if (blocks & STMPE_BLOCK_PWM)
mask |= STMPE1601_SYS_CTRL_ENABLE_SPWM;
else
mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM;
return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
enable ? mask : 0);
......@@ -986,9 +996,6 @@ static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np)
int base = 0;
int num_irqs = stmpe->variant->num_irqs;
if (!np)
base = stmpe->irq_base;
stmpe->domain = irq_domain_add_simple(np, num_irqs, base,
&stmpe_irq_ops, stmpe);
if (!stmpe->domain) {
......@@ -1067,7 +1074,7 @@ static int stmpe_chip_init(struct stmpe *stmpe)
static int stmpe_add_device(struct stmpe *stmpe, const struct mfd_cell *cell)
{
return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
NULL, stmpe->irq_base, stmpe->domain);
NULL, 0, stmpe->domain);
}
static int stmpe_devices_init(struct stmpe *stmpe)
......@@ -1171,12 +1178,23 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
stmpe->dev = ci->dev;
stmpe->client = ci->client;
stmpe->pdata = pdata;
stmpe->irq_base = pdata->irq_base;
stmpe->ci = ci;
stmpe->partnum = partnum;
stmpe->variant = stmpe_variant_info[partnum];
stmpe->regs = stmpe->variant->regs;
stmpe->num_gpios = stmpe->variant->num_gpios;
stmpe->vcc = devm_regulator_get_optional(ci->dev, "vcc");
if (!IS_ERR(stmpe->vcc)) {
ret = regulator_enable(stmpe->vcc);
if (ret)
dev_warn(ci->dev, "failed to enable VCC supply\n");
}
stmpe->vio = devm_regulator_get_optional(ci->dev, "vio");
if (!IS_ERR(stmpe->vio)) {
ret = regulator_enable(stmpe->vio);
if (ret)
dev_warn(ci->dev, "failed to enable VIO supply\n");
}
dev_set_drvdata(stmpe->dev, stmpe);
if (ci->init)
......@@ -1243,6 +1261,11 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
int stmpe_remove(struct stmpe *stmpe)
{
if (!IS_ERR(stmpe->vio))
regulator_disable(stmpe->vio);
if (!IS_ERR(stmpe->vcc))
regulator_disable(stmpe->vcc);
mfd_remove_devices(stmpe->dev);
return 0;
......
......@@ -192,7 +192,7 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3)
#define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1)
#define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0)
#define STMPE1601_SYS_CTRL_ENABLE_SPWM (1 << 0)
/* The 1601/2403 share the same masks */
#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7)
......
......@@ -32,14 +32,6 @@
#define NUM_INT_REG 2
#define TOTAL_NUM_REG 0x18
/* interrupt status registers */
#define TPS65090_INT_STS 0x0
#define TPS65090_INT_STS2 0x1
/* interrupt mask registers */
#define TPS65090_INT_MSK 0x2
#define TPS65090_INT_MSK2 0x3
#define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1
#define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2
#define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3
......@@ -64,11 +56,16 @@ static struct resource charger_resources[] = {
}
};
static const struct mfd_cell tps65090s[] = {
{
enum tps65090_cells {
PMIC = 0,
CHARGER = 1,
};
static struct mfd_cell tps65090s[] = {
[PMIC] = {
.name = "tps65090-pmic",
},
{
[CHARGER] = {
.name = "tps65090-charger",
.num_resources = ARRAY_SIZE(charger_resources),
.resources = &charger_resources[0],
......@@ -139,17 +136,26 @@ static struct regmap_irq_chip tps65090_irq_chip = {
.irqs = tps65090_irqs,
.num_irqs = ARRAY_SIZE(tps65090_irqs),
.num_regs = NUM_INT_REG,
.status_base = TPS65090_INT_STS,
.mask_base = TPS65090_INT_MSK,
.status_base = TPS65090_REG_INTR_STS,
.mask_base = TPS65090_REG_INTR_MASK,
.mask_invert = true,
};
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2))
return true;
else
/* Nearly all registers have status bits mixed in, except a few */
switch (reg) {
case TPS65090_REG_INTR_MASK:
case TPS65090_REG_INTR_MASK2:
case TPS65090_REG_CG_CTRL0:
case TPS65090_REG_CG_CTRL1:
case TPS65090_REG_CG_CTRL2:
case TPS65090_REG_CG_CTRL3:
case TPS65090_REG_CG_CTRL4:
case TPS65090_REG_CG_CTRL5:
return false;
}
return true;
}
static const struct regmap_config tps65090_regmap_config = {
......@@ -211,6 +217,9 @@ static int tps65090_i2c_probe(struct i2c_client *client,
"IRQ init failed with err: %d\n", ret);
return ret;
}
} else {
/* Don't tell children they have an IRQ that'll never fire */
tps65090s[CHARGER].num_resources = 0;
}
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
......
......@@ -495,6 +495,10 @@ static void tps6586x_print_version(struct i2c_client *client, int version)
case TPS658623:
name = "TPS658623";
break;
case TPS658640:
case TPS658640v2:
name = "TPS658640";
break;
case TPS658643:
name = "TPS658643";
break;
......
......@@ -98,7 +98,11 @@
#define TWL4030_BASEADD_BACKUP 0x0014
#define TWL4030_BASEADD_INT 0x002E
#define TWL4030_BASEADD_PM_MASTER 0x0036
#define TWL4030_BASEADD_PM_RECEIVER 0x005B
#define TWL4030_DCDC_GLOBAL_CFG 0x06
#define SMARTREFLEX_ENABLE BIT(3)
#define TWL4030_BASEADD_RTC 0x001C
#define TWL4030_BASEADD_SECURED_REG 0x0000
......@@ -1204,6 +1208,11 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
* Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
* SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
*
* Also, always enable SmartReflex bit as that's needed for omaps to
* to do anything over I2C4 for voltage scaling even if SmartReflex
* is disabled. Without the SmartReflex bit omap sys_clkreq idle
* signal will never trigger for retention idle.
*/
if (twl_class_is_4030()) {
u8 temp;
......@@ -1212,6 +1221,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
TWL4030_DCDC_GLOBAL_CFG);
temp |= SMARTREFLEX_ENABLE;
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
TWL4030_DCDC_GLOBAL_CFG);
}
if (node) {
......
......@@ -694,3 +694,10 @@ config MMC_REALTEK_PCI
help
Say Y here to include driver code to support SD/MMC card interface
of Realtek PCI-E card reader
config MMC_REALTEK_USB
tristate "Realtek USB SD/MMC Card Interface Driver"
depends on MFD_RTSX_USB
help
Say Y here to include driver code to support SD/MMC card interface
of Realtek RTS5129/39 series card reader
......@@ -52,6 +52,7 @@ obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
......
/* Realtek USB SD/MMC 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/slab.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/card.h>
#include <linux/scatterlist.h>
#include <linux/pm_runtime.h>
#include <linux/mfd/rtsx_usb.h>
#include <asm/unaligned.h>
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
#include <linux/leds.h>
#include <linux/workqueue.h>
#define RTSX_USB_USE_LEDS_CLASS
#endif
struct rtsx_usb_sdmmc {
struct platform_device *pdev;
struct rtsx_ucr *ucr;
struct mmc_host *mmc;
struct mmc_request *mrq;
struct mutex host_mutex;
u8 ssc_depth;
unsigned int clock;
bool vpclk;
bool double_clk;
bool host_removal;
bool card_exist;
bool initial_mode;
bool ddr_mode;
unsigned char power_mode;
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
struct led_classdev led;
char led_name[32];
struct work_struct led_work;
#endif
};
static inline struct device *sdmmc_dev(struct rtsx_usb_sdmmc *host)
{
return &(host->pdev->dev);
}
static inline void sd_clear_error(struct rtsx_usb_sdmmc *host)
{
struct rtsx_ucr *ucr = host->ucr;
rtsx_usb_ep0_write_register(ucr, CARD_STOP,
SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
rtsx_usb_clear_dma_err(ucr);
rtsx_usb_clear_fsm_err(ucr);
}
#ifdef DEBUG
static void sd_print_debug_regs(struct rtsx_usb_sdmmc *host)
{
struct rtsx_ucr *ucr = host->ucr;
u8 val = 0;
rtsx_usb_ep0_read_register(ucr, SD_STAT1, &val);
dev_dbg(sdmmc_dev(host), "SD_STAT1: 0x%x\n", val);
rtsx_usb_ep0_read_register(ucr, SD_STAT2, &val);
dev_dbg(sdmmc_dev(host), "SD_STAT2: 0x%x\n", val);
rtsx_usb_ep0_read_register(ucr, SD_BUS_STAT, &val);
dev_dbg(sdmmc_dev(host), "SD_BUS_STAT: 0x%x\n", val);
}
#else
#define sd_print_debug_regs(host)
#endif /* DEBUG */
static int sd_read_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd,
u16 byte_cnt, u8 *buf, int buf_len, int timeout)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
u8 trans_mode;
if (!buf)
buf_len = 0;
rtsx_usb_init_cmd(ucr);
if (cmd != NULL) {
dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__
, cmd->opcode);
if (cmd->opcode == MMC_SEND_TUNING_BLOCK)
trans_mode = SD_TM_AUTO_TUNING;
else
trans_mode = SD_TM_NORMAL_READ;
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD1, 0xFF, (u8)(cmd->arg >> 24));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD2, 0xFF, (u8)(cmd->arg >> 16));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD3, 0xFF, (u8)(cmd->arg >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD4, 0xFF, (u8)cmd->arg);
} else {
trans_mode = SD_TM_AUTO_READ_3;
}
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H,
0xFF, (u8)(byte_cnt >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
if (trans_mode != SD_TM_AUTO_TUNING)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER,
0xFF, trans_mode | SD_TRANSFER_START);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
if (cmd != NULL) {
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0);
}
err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout);
if (err) {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_send_cmd failed (err = %d)\n", err);
return err;
}
err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout);
if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) {
sd_print_debug_regs(host);
if (!err) {
dev_dbg(sdmmc_dev(host),
"Transfer failed (SD_TRANSFER = %02x)\n",
ucr->rsp_buf[0]);
err = -EIO;
} else {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_get_rsp failed (err = %d)\n", err);
}
return err;
}
if (cmd != NULL) {
cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1);
dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
cmd->resp[0]);
}
if (buf && buf_len) {
/* 2-byte aligned part */
err = rtsx_usb_read_ppbuf(ucr, buf, byte_cnt - (byte_cnt % 2));
if (err) {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_read_ppbuf failed (err = %d)\n", err);
return err;
}
/* unaligned byte */
if (byte_cnt % 2)
return rtsx_usb_read_register(ucr,
PPBUF_BASE2 + byte_cnt,
buf + byte_cnt - 1);
}
return 0;
}
static int sd_write_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd,
u16 byte_cnt, u8 *buf, int buf_len, int timeout)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
u8 trans_mode;
if (!buf)
buf_len = 0;
if (buf && buf_len) {
err = rtsx_usb_write_ppbuf(ucr, buf, buf_len);
if (err) {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_write_ppbuf failed (err = %d)\n",
err);
return err;
}
}
trans_mode = (cmd != NULL) ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3;
rtsx_usb_init_cmd(ucr);
if (cmd != NULL) {
dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__,
cmd->opcode);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD1, 0xFF, (u8)(cmd->arg >> 24));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD2, 0xFF, (u8)(cmd->arg >> 16));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD3, 0xFF, (u8)(cmd->arg >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CMD4, 0xFF, (u8)cmd->arg);
}
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H,
0xFF, (u8)(byte_cnt >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
trans_mode | SD_TRANSFER_START);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
if (cmd != NULL) {
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0);
}
err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout);
if (err) {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_send_cmd failed (err = %d)\n", err);
return err;
}
err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout);
if (err) {
sd_print_debug_regs(host);
dev_dbg(sdmmc_dev(host),
"rtsx_usb_get_rsp failed (err = %d)\n", err);
return err;
}
if (cmd != NULL) {
cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1);
dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
cmd->resp[0]);
}
return 0;
}
static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
struct mmc_command *cmd)
{
struct rtsx_ucr *ucr = host->ucr;
u8 cmd_idx = (u8)cmd->opcode;
u32 arg = cmd->arg;
int err = 0;
int timeout = 100;
int i;
u8 *ptr;
int stat_idx = 0;
int len = 2;
u8 rsp_type;
dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
__func__, cmd_idx, arg);
/* Response type:
* R0
* R1, R5, R6, R7
* R1b
* R2
* R3, R4
*/
switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE:
rsp_type = SD_RSP_TYPE_R0;
break;
case MMC_RSP_R1:
rsp_type = SD_RSP_TYPE_R1;
break;
case MMC_RSP_R1 & ~MMC_RSP_CRC:
rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
break;
case MMC_RSP_R1B:
rsp_type = SD_RSP_TYPE_R1b;
break;
case MMC_RSP_R2:
rsp_type = SD_RSP_TYPE_R2;
break;
case MMC_RSP_R3:
rsp_type = SD_RSP_TYPE_R3;
break;
default:
dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n");
err = -EINVAL;
goto out;
}
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = 3000;
if (cmd->opcode == SD_SWITCH_VOLTAGE) {
err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
SD_CLK_TOGGLE_EN);
if (err)
goto out;
}
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER,
0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END | SD_STAT_IDLE,
SD_TRANSFER_END | SD_STAT_IDLE);
if (rsp_type == SD_RSP_TYPE_R2) {
/* Read data from ping-pong buffer */
for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
stat_idx = 16;
} else if (rsp_type != SD_RSP_TYPE_R0) {
/* Read data from SD_CMDx registers */
for (i = SD_CMD0; i <= SD_CMD4; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
stat_idx = 5;
}
len += stat_idx;
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_STAT1, 0, 0);
err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (err) {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_send_cmd error (err = %d)\n", err);
goto out;
}
err = rtsx_usb_get_rsp(ucr, len, timeout);
if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) {
sd_print_debug_regs(host);
sd_clear_error(host);
if (!err) {
dev_dbg(sdmmc_dev(host),
"Transfer failed (SD_TRANSFER = %02x)\n",
ucr->rsp_buf[0]);
err = -EIO;
} else {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_get_rsp failed (err = %d)\n", err);
}
goto out;
}
if (rsp_type == SD_RSP_TYPE_R0) {
err = 0;
goto out;
}
/* Skip result of CHECK_REG_CMD */
ptr = ucr->rsp_buf + 1;
/* Check (Start,Transmission) bit of Response */
if ((ptr[0] & 0xC0) != 0) {
err = -EILSEQ;
dev_dbg(sdmmc_dev(host), "Invalid response bit\n");
goto out;
}
/* Check CRC7 */
if (!(rsp_type & SD_NO_CHECK_CRC7)) {
if (ptr[stat_idx] & SD_CRC7_ERR) {
err = -EILSEQ;
dev_dbg(sdmmc_dev(host), "CRC7 error\n");
goto out;
}
}
if (rsp_type == SD_RSP_TYPE_R2) {
for (i = 0; i < 4; i++) {
cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4);
dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n",
i, cmd->resp[i]);
}
} else {
cmd->resp[0] = get_unaligned_be32(ptr + 1);
dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
cmd->resp[0]);
}
out:
cmd->error = err;
}
static int sd_rw_multi(struct rtsx_usb_sdmmc *host, struct mmc_request *mrq)
{
struct rtsx_ucr *ucr = host->ucr;
struct mmc_data *data = mrq->data;
int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
u8 cfg2, trans_mode;
int err;
u8 flag;
size_t data_len = data->blksz * data->blocks;
unsigned int pipe;
if (read) {
dev_dbg(sdmmc_dev(host), "%s: read %zu bytes\n",
__func__, data_len);
cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
trans_mode = SD_TM_AUTO_READ_3;
} else {
dev_dbg(sdmmc_dev(host), "%s: write %zu bytes\n",
__func__, data_len);
cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0;
trans_mode = SD_TM_AUTO_WRITE_3;
}
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L,
0xFF, (u8)data->blocks);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H,
0xFF, (u8)(data->blocks >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, RING_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3,
0xFF, (u8)(data_len >> 24));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2,
0xFF, (u8)(data_len >> 16));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1,
0xFF, (u8)(data_len >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0,
0xFF, (u8)data_len);
if (read) {
flag = MODE_CDIR;
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
0x03 | DMA_PACK_SIZE_MASK,
DMA_DIR_FROM_CARD | DMA_EN | DMA_512);
} else {
flag = MODE_CDOR;
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL,
0x03 | DMA_PACK_SIZE_MASK,
DMA_DIR_TO_CARD | DMA_EN | DMA_512);
}
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
trans_mode | SD_TRANSFER_START);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
err = rtsx_usb_send_cmd(ucr, flag, 100);
if (err)
return err;
if (read)
pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN);
else
pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT);
err = rtsx_usb_transfer_data(ucr, pipe, data->sg, data_len,
data->sg_len, NULL, 10000);
if (err) {
dev_dbg(sdmmc_dev(host), "rtsx_usb_transfer_data error %d\n"
, err);
sd_clear_error(host);
return err;
}
return rtsx_usb_get_rsp(ucr, 1, 2000);
}
static inline void sd_enable_initial_mode(struct rtsx_usb_sdmmc *host)
{
rtsx_usb_write_register(host->ucr, SD_CFG1,
SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128);
}
static inline void sd_disable_initial_mode(struct rtsx_usb_sdmmc *host)
{
rtsx_usb_write_register(host->ucr, SD_CFG1,
SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
}
static void sd_normal_rw(struct rtsx_usb_sdmmc *host,
struct mmc_request *mrq)
{
struct mmc_command *cmd = mrq->cmd;
struct mmc_data *data = mrq->data;
u8 *buf;
buf = kzalloc(data->blksz, GFP_NOIO);
if (!buf) {
cmd->error = -ENOMEM;
return;
}
if (data->flags & MMC_DATA_READ) {
if (host->initial_mode)
sd_disable_initial_mode(host);
cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf,
data->blksz, 200);
if (host->initial_mode)
sd_enable_initial_mode(host);
sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz);
} else {
sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz);
cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf,
data->blksz, 200);
}
kfree(buf);
}
static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n",
__func__, tx ? "TX" : "RX", sample_point);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
if (tx)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
0x0F, sample_point);
else
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK1_CTL,
0x0F, sample_point);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err)
return err;
return 0;
}
static inline u32 get_phase_point(u32 phase_map, unsigned int idx)
{
idx &= MAX_PHASE;
return phase_map & (1 << idx);
}
static int get_phase_len(u32 phase_map, unsigned int idx)
{
int i;
for (i = 0; i < MAX_PHASE + 1; i++) {
if (get_phase_point(phase_map, idx + i) == 0)
return i;
}
return MAX_PHASE + 1;
}
static u8 sd_search_final_phase(struct rtsx_usb_sdmmc *host, u32 phase_map)
{
int start = 0, len = 0;
int start_final = 0, len_final = 0;
u8 final_phase = 0xFF;
if (phase_map == 0) {
dev_dbg(sdmmc_dev(host), "Phase: [map:%x]\n", phase_map);
return final_phase;
}
while (start < MAX_PHASE + 1) {
len = get_phase_len(phase_map, start);
if (len_final < len) {
start_final = start;
len_final = len;
}
start += len ? len : 1;
}
final_phase = (start_final + len_final / 2) & MAX_PHASE;
dev_dbg(sdmmc_dev(host), "Phase: [map:%x] [maxlen:%d] [final:%d]\n",
phase_map, len_final, final_phase);
return final_phase;
}
static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host)
{
int err, i;
u8 val = 0;
for (i = 0; i < 100; i++) {
err = rtsx_usb_ep0_read_register(host->ucr,
SD_DATA_STATE, &val);
if (val & SD_DATA_IDLE)
return;
usleep_range(100, 1000);
}
}
static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host,
u8 opcode, u8 sample_point)
{
int err;
struct mmc_command cmd = {0};
err = sd_change_phase(host, sample_point, 0);
if (err)
return err;
cmd.opcode = MMC_SEND_TUNING_BLOCK;
err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100);
if (err) {
/* Wait till SD DATA IDLE */
sd_wait_data_idle(host);
sd_clear_error(host);
return err;
}
return 0;
}
static void sd_tuning_phase(struct rtsx_usb_sdmmc *host,
u8 opcode, u16 *phase_map)
{
int err, i;
u16 raw_phase_map = 0;
for (i = MAX_PHASE; i >= 0; i--) {
err = sd_tuning_rx_cmd(host, opcode, (u8)i);
if (!err)
raw_phase_map |= 1 << i;
}
if (phase_map)
*phase_map = raw_phase_map;
}
static int sd_tuning_rx(struct rtsx_usb_sdmmc *host, u8 opcode)
{
int err, i;
u16 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map;
u8 final_phase;
/* setting fixed default TX phase */
err = sd_change_phase(host, 0x01, 1);
if (err) {
dev_dbg(sdmmc_dev(host), "TX phase setting failed\n");
return err;
}
/* tuning RX phase */
for (i = 0; i < RX_TUNING_CNT; i++) {
sd_tuning_phase(host, opcode, &(raw_phase_map[i]));
if (raw_phase_map[i] == 0)
break;
}
phase_map = 0xFFFF;
for (i = 0; i < RX_TUNING_CNT; i++) {
dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%04x\n",
i, raw_phase_map[i]);
phase_map &= raw_phase_map[i];
}
dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%04x\n", phase_map);
if (phase_map) {
final_phase = sd_search_final_phase(host, phase_map);
if (final_phase == 0xFF)
return -EINVAL;
err = sd_change_phase(host, final_phase, 0);
if (err)
return err;
} else {
return -EINVAL;
}
return 0;
}
static int sdmmc_get_ro(struct mmc_host *mmc)
{
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host->ucr;
int err;
u16 val;
if (host->host_removal)
return -ENOMEDIUM;
mutex_lock(&ucr->dev_mutex);
/* Check SD card detect */
err = rtsx_usb_get_card_status(ucr, &val);
mutex_unlock(&ucr->dev_mutex);
/* Treat failed detection as non-ro */
if (err)
return 0;
if (val & SD_WP)
return 1;
return 0;
}
static int sdmmc_get_cd(struct mmc_host *mmc)
{
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host->ucr;
int err;
u16 val;
if (host->host_removal)
return -ENOMEDIUM;
mutex_lock(&ucr->dev_mutex);
/* Check SD card detect */
err = rtsx_usb_get_card_status(ucr, &val);
mutex_unlock(&ucr->dev_mutex);
/* Treat failed detection as non-exist */
if (err)
goto no_card;
if (val & SD_CD) {
host->card_exist = true;
return 1;
}
no_card:
host->card_exist = false;
return 0;
}
static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host->ucr;
struct mmc_command *cmd = mrq->cmd;
struct mmc_data *data = mrq->data;
unsigned int data_size = 0;
dev_dbg(sdmmc_dev(host), "%s\n", __func__);
if (host->host_removal) {
cmd->error = -ENOMEDIUM;
goto finish;
}
if ((!host->card_exist)) {
cmd->error = -ENOMEDIUM;
goto finish_detect_card;
}
/*
* Reject SDIO CMDs to speed up card identification
* since unsupported
*/
if (cmd->opcode == SD_IO_SEND_OP_COND ||
cmd->opcode == SD_IO_RW_DIRECT ||
cmd->opcode == SD_IO_RW_EXTENDED) {
cmd->error = -EINVAL;
goto finish;
}
mutex_lock(&ucr->dev_mutex);
mutex_lock(&host->host_mutex);
host->mrq = mrq;
mutex_unlock(&host->host_mutex);
if (mrq->data)
data_size = data->blocks * data->blksz;
if (!data_size) {
sd_send_cmd_get_rsp(host, cmd);
} else if ((!(data_size % 512) && cmd->opcode != MMC_SEND_EXT_CSD) ||
mmc_op_multi(cmd->opcode)) {
sd_send_cmd_get_rsp(host, cmd);
if (!cmd->error) {
sd_rw_multi(host, mrq);
if (mmc_op_multi(cmd->opcode) && mrq->stop) {
sd_send_cmd_get_rsp(host, mrq->stop);
rtsx_usb_write_register(ucr, MC_FIFO_CTL,
FIFO_FLUSH, FIFO_FLUSH);
}
}
} else {
sd_normal_rw(host, mrq);
}
if (mrq->data) {
if (cmd->error || data->error)
data->bytes_xfered = 0;
else
data->bytes_xfered = data->blocks * data->blksz;
}
mutex_unlock(&ucr->dev_mutex);
finish_detect_card:
if (cmd->error) {
/*
* detect card when fail to update card existence state and
* speed up card removal when retry
*/
sdmmc_get_cd(mmc);
dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
}
finish:
mutex_lock(&host->host_mutex);
host->mrq = NULL;
mutex_unlock(&host->host_mutex);
mmc_request_done(mmc, mrq);
}
static int sd_set_bus_width(struct rtsx_usb_sdmmc *host,
unsigned char bus_width)
{
int err = 0;
u8 width[] = {
[MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT,
[MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT,
[MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT,
};
if (bus_width <= MMC_BUS_WIDTH_8)
err = rtsx_usb_write_register(host->ucr, SD_CFG1,
0x03, width[bus_width]);
return err;
}
static int sd_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 sd_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 sd_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, 0xAA);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0xAA);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA9);
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 sd_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, 0xA5);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x9A);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA5);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x9A);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x65);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x5A);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int sd_power_on(struct rtsx_usb_sdmmc *host)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(sdmmc_dev(host), "%s\n", __func__);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE,
CARD_SHARE_MASK, CARD_SHARE_SD);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN,
SD_CLK_EN, SD_CLK_EN);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err)
return err;
if (CHECK_PKG(ucr, LQFP48))
err = sd_pull_ctl_enable_lqfp48(ucr);
else
err = sd_pull_ctl_enable_qfn24(ucr);
if (err)
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|LDO3318_PWR_MASK, POWER_ON|LDO_ON);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE,
SD_OUTPUT_EN, SD_OUTPUT_EN);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
static int sd_power_off(struct rtsx_usb_sdmmc *host)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(sdmmc_dev(host), "%s\n", __func__);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
POWER_MASK, POWER_OFF);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
POWER_MASK|LDO3318_PWR_MASK, POWER_OFF|LDO_SUSPEND);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err)
return err;
if (CHECK_PKG(ucr, LQFP48))
return sd_pull_ctl_disable_lqfp48(ucr);
return sd_pull_ctl_disable_qfn24(ucr);
}
static int sd_set_power_mode(struct rtsx_usb_sdmmc *host,
unsigned char power_mode)
{
int err;
if (power_mode != MMC_POWER_OFF)
power_mode = MMC_POWER_ON;
if (power_mode == host->power_mode)
return 0;
if (power_mode == MMC_POWER_OFF) {
err = sd_power_off(host);
pm_runtime_put(sdmmc_dev(host));
} else {
pm_runtime_get_sync(sdmmc_dev(host));
err = sd_power_on(host);
}
if (!err)
host->power_mode = power_mode;
return err;
}
static int sd_set_timing(struct rtsx_usb_sdmmc *host,
unsigned char timing, bool *ddr_mode)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
*ddr_mode = false;
rtsx_usb_init_cmd(ucr);
switch (timing) {
case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_UHS_SDR50:
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
0x0C | SD_ASYNC_FIFO_RST,
SD_30_MODE | SD_ASYNC_FIFO_RST);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
break;
case MMC_TIMING_UHS_DDR50:
*ddr_mode = true;
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
0x0C | SD_ASYNC_FIFO_RST,
SD_DDR_MODE | SD_ASYNC_FIFO_RST);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
DDR_VAR_RX_DAT | DDR_VAR_RX_CMD,
DDR_VAR_RX_DAT | DDR_VAR_RX_CMD);
break;
case MMC_TIMING_MMC_HS:
case MMC_TIMING_SD_HS:
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1,
0x0C, SD_20_MODE);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
SD20_TX_SEL_MASK, SD20_TX_14_AHEAD);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
SD20_RX_SEL_MASK, SD20_RX_14_DELAY);
break;
default:
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_CFG1, 0x0C, SD_20_MODE);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
SD_PUSH_POINT_CTL, 0xFF, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
SD20_RX_SEL_MASK, SD20_RX_POS_EDGE);
break;
}
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
return err;
}
static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host->ucr;
dev_dbg(sdmmc_dev(host), "%s\n", __func__);
mutex_lock(&ucr->dev_mutex);
if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) {
mutex_unlock(&ucr->dev_mutex);
return;
}
sd_set_power_mode(host, ios->power_mode);
sd_set_bus_width(host, ios->bus_width);
sd_set_timing(host, ios->timing, &host->ddr_mode);
host->vpclk = false;
host->double_clk = true;
switch (ios->timing) {
case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_UHS_SDR50:
host->ssc_depth = SSC_DEPTH_2M;
host->vpclk = true;
host->double_clk = false;
break;
case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_UHS_SDR25:
host->ssc_depth = SSC_DEPTH_1M;
break;
default:
host->ssc_depth = SSC_DEPTH_512K;
break;
}
host->initial_mode = (ios->clock <= 1000000) ? true : false;
host->clock = ios->clock;
rtsx_usb_switch_clock(host->ucr, host->clock, host->ssc_depth,
host->initial_mode, host->double_clk, host->vpclk);
mutex_unlock(&ucr->dev_mutex);
dev_dbg(sdmmc_dev(host), "%s end\n", __func__);
}
static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host->ucr;
int err = 0;
dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n",
__func__, ios->signal_voltage);
if (host->host_removal)
return -ENOMEDIUM;
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120)
return -EPERM;
mutex_lock(&ucr->dev_mutex);
err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD);
if (err) {
mutex_unlock(&ucr->dev_mutex);
return err;
}
/* Let mmc core do the busy checking, simply stop the forced-toggle
* clock(while issuing CMD11) and switch voltage.
*/
rtsx_usb_init_cmd(ucr);
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL,
SD_IO_USING_1V8, SD_IO_USING_3V3);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG,
TUNE_SD18_MASK, TUNE_SD18_3V3);
} else {
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
SD_CLK_FORCE_STOP);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL,
SD_IO_USING_1V8, SD_IO_USING_1V8);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG,
TUNE_SD18_MASK, TUNE_SD18_1V8);
}
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
mutex_unlock(&ucr->dev_mutex);
return err;
}
static int sdmmc_card_busy(struct mmc_host *mmc)
{
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host->ucr;
int err;
u8 stat;
u8 mask = SD_DAT3_STATUS | SD_DAT2_STATUS | SD_DAT1_STATUS
| SD_DAT0_STATUS;
dev_dbg(sdmmc_dev(host), "%s\n", __func__);
mutex_lock(&ucr->dev_mutex);
err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
SD_CLK_TOGGLE_EN);
if (err)
goto out;
mdelay(1);
err = rtsx_usb_read_register(ucr, SD_BUS_STAT, &stat);
if (err)
goto out;
err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
out:
mutex_unlock(&ucr->dev_mutex);
if (err)
return err;
/* check if any pin between dat[0:3] is low */
if ((stat & mask) != mask)
return 1;
else
return 0;
}
static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct rtsx_usb_sdmmc *host = mmc_priv(mmc);
struct rtsx_ucr *ucr = host->ucr;
int err = 0;
if (host->host_removal)
return -ENOMEDIUM;
mutex_lock(&ucr->dev_mutex);
if (!host->ddr_mode)
err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK);
mutex_unlock(&ucr->dev_mutex);
return err;
}
static const struct mmc_host_ops rtsx_usb_sdmmc_ops = {
.request = sdmmc_request,
.set_ios = sdmmc_set_ios,
.get_ro = sdmmc_get_ro,
.get_cd = sdmmc_get_cd,
.start_signal_voltage_switch = sdmmc_switch_voltage,
.card_busy = sdmmc_card_busy,
.execute_tuning = sdmmc_execute_tuning,
};
#ifdef RTSX_USB_USE_LEDS_CLASS
static void rtsx_usb_led_control(struct led_classdev *led,
enum led_brightness brightness)
{
struct rtsx_usb_sdmmc *host = container_of(led,
struct rtsx_usb_sdmmc, led);
if (host->host_removal)
return;
host->led.brightness = brightness;
schedule_work(&host->led_work);
}
static void rtsx_usb_update_led(struct work_struct *work)
{
struct rtsx_usb_sdmmc *host =
container_of(work, struct rtsx_usb_sdmmc, led_work);
struct rtsx_ucr *ucr = host->ucr;
mutex_lock(&ucr->dev_mutex);
if (host->led.brightness == LED_OFF)
rtsx_usb_turn_off_led(ucr);
else
rtsx_usb_turn_on_led(ucr);
mutex_unlock(&ucr->dev_mutex);
}
#endif
static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
{
struct mmc_host *mmc = host->mmc;
mmc->f_min = 250000;
mmc->f_max = 208000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
MMC_CAP_NEEDS_POLL;
mmc->max_current_330 = 400;
mmc->max_current_180 = 800;
mmc->ops = &rtsx_usb_sdmmc_ops;
mmc->max_segs = 256;
mmc->max_seg_size = 65536;
mmc->max_blk_size = 512;
mmc->max_blk_count = 65535;
mmc->max_req_size = 524288;
host->power_mode = MMC_POWER_OFF;
}
static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct rtsx_usb_sdmmc *host;
struct rtsx_ucr *ucr;
#ifdef RTSX_USB_USE_LEDS_CLASS
int err;
#endif
ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
if (!ucr)
return -ENXIO;
dev_dbg(&(pdev->dev), ": Realtek USB SD/MMC controller found\n");
mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
if (!mmc)
return -ENOMEM;
host = mmc_priv(mmc);
host->ucr = ucr;
host->mmc = mmc;
host->pdev = pdev;
platform_set_drvdata(pdev, host);
mutex_init(&host->host_mutex);
rtsx_usb_init_host(host);
pm_runtime_enable(&pdev->dev);
#ifdef RTSX_USB_USE_LEDS_CLASS
snprintf(host->led_name, sizeof(host->led_name),
"%s::", mmc_hostname(mmc));
host->led.name = host->led_name;
host->led.brightness = LED_OFF;
host->led.default_trigger = mmc_hostname(mmc);
host->led.brightness_set = rtsx_usb_led_control;
err = led_classdev_register(mmc_dev(mmc), &host->led);
if (err)
dev_err(&(pdev->dev),
"Failed to register LED device: %d\n", err);
INIT_WORK(&host->led_work, rtsx_usb_update_led);
#endif
mmc_add_host(mmc);
return 0;
}
static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
{
struct rtsx_usb_sdmmc *host = platform_get_drvdata(pdev);
struct mmc_host *mmc;
if (!host)
return 0;
mmc = host->mmc;
host->host_removal = true;
mutex_lock(&host->host_mutex);
if (host->mrq) {
dev_dbg(&(pdev->dev),
"%s: Controller removed during transfer\n",
mmc_hostname(mmc));
host->mrq->cmd->error = -ENOMEDIUM;
if (host->mrq->stop)
host->mrq->stop->error = -ENOMEDIUM;
mmc_request_done(mmc, host->mrq);
}
mutex_unlock(&host->host_mutex);
mmc_remove_host(mmc);
#ifdef RTSX_USB_USE_LEDS_CLASS
cancel_work_sync(&host->led_work);
led_classdev_unregister(&host->led);
#endif
mmc_free_host(mmc);
pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
dev_dbg(&(pdev->dev),
": Realtek USB SD/MMC module has been removed\n");
return 0;
}
static struct platform_device_id rtsx_usb_sdmmc_ids[] = {
{
.name = "rtsx_usb_sdmmc",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids);
static struct platform_driver rtsx_usb_sdmmc_driver = {
.probe = rtsx_usb_sdmmc_drv_probe,
.remove = rtsx_usb_sdmmc_drv_remove,
.id_table = rtsx_usb_sdmmc_ids,
.driver = {
.owner = THIS_MODULE,
.name = "rtsx_usb_sdmmc",
},
};
module_platform_driver(rtsx_usb_sdmmc_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
MODULE_DESCRIPTION("Realtek USB SD/MMC Card Host Driver");
......@@ -28,17 +28,6 @@
#include <linux/mfd/tps65090.h>
#define TPS65090_REG_INTR_STS 0x00
#define TPS65090_REG_INTR_MASK 0x02
#define TPS65090_REG_CG_CTRL0 0x04
#define TPS65090_REG_CG_CTRL1 0x05
#define TPS65090_REG_CG_CTRL2 0x06
#define TPS65090_REG_CG_CTRL3 0x07
#define TPS65090_REG_CG_CTRL4 0x08
#define TPS65090_REG_CG_CTRL5 0x09
#define TPS65090_REG_CG_STATUS1 0x0a
#define TPS65090_REG_CG_STATUS2 0x0b
#define TPS65090_CHARGER_ENABLE BIT(0)
#define TPS65090_VACG BIT(1)
#define TPS65090_NOITERM BIT(5)
......
......@@ -266,11 +266,12 @@ config REGULATOR_LP8788
This driver supports LP8788 voltage regulator chip.
config REGULATOR_MAX14577
tristate "Maxim 14577 regulator"
tristate "Maxim 14577/77836 regulator"
depends on MFD_MAX14577
help
This driver controls a Maxim 14577 regulator via I2C bus.
The regulators include safeout LDO and current regulator 'CHARGER'.
This driver controls a Maxim MAX14577/77836 regulator via I2C bus.
The MAX14577 regulators include safeout LDO and charger current
regulator. The MAX77836 has two additional LDOs.
config REGULATOR_MAX1586
tristate "Maxim 1586/1587 voltage regulator"
......
......@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/gpio.h>
#include <linux/slab.h>
......@@ -178,6 +179,42 @@ static const struct regulator_init_data arizona_ldo1_default = {
.num_consumer_supplies = 1,
};
static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
struct regulator_config *config)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_ldo1 *ldo1 = config->driver_data;
struct device_node *init_node, *dcvdd_node;
struct regulator_init_data *init_data;
pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true);
init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1");
dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0);
if (init_node) {
config->of_node = init_node;
init_data = of_get_regulator_init_data(arizona->dev, init_node);
if (init_data) {
init_data->consumer_supplies = &ldo1->supply;
init_data->num_consumer_supplies = 1;
if (dcvdd_node && dcvdd_node != init_node)
arizona->external_dcvdd = true;
pdata->ldo1 = init_data;
}
} else if (dcvdd_node) {
arizona->external_dcvdd = true;
}
of_node_put(dcvdd_node);
return 0;
}
static int arizona_ldo1_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
......@@ -186,6 +223,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
struct arizona_ldo1 *ldo1;
int ret;
arizona->external_dcvdd = false;
ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
if (!ldo1)
return -ENOMEM;
......@@ -216,6 +255,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
config.dev = arizona->dev;
config.driver_data = ldo1;
config.regmap = arizona->regmap;
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_ldo1_of_get_pdata(arizona, &config);
if (ret < 0)
return ret;
}
}
config.ena_gpio = arizona->pdata.ldoena;
if (arizona->pdata.ldo1)
......@@ -223,6 +271,13 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
else
config.init_data = &ldo1->init_data;
/*
* LDO1 can only be used to supply DCVDD so if it has no
* consumers then DCVDD is supplied externally.
*/
if (config.init_data->num_consumer_supplies == 0)
arizona->external_dcvdd = true;
ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(ldo1->regulator)) {
ret = PTR_ERR(ldo1->regulator);
......@@ -231,6 +286,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
return ret;
}
of_node_put(config.of_node);
platform_set_drvdata(pdev, ldo1);
return 0;
......
......@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
......@@ -195,6 +196,32 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
.num_consumer_supplies = 1,
};
static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
struct regulator_config *config)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_micsupp *micsupp = config->driver_data;
struct device_node *np;
struct regulator_init_data *init_data;
np = of_get_child_by_name(arizona->dev->of_node, "micvdd");
if (np) {
config->of_node = np;
init_data = of_get_regulator_init_data(arizona->dev, np);
if (init_data) {
init_data->consumer_supplies = &micsupp->supply;
init_data->num_consumer_supplies = 1;
pdata->micvdd = init_data;
}
}
return 0;
}
static int arizona_micsupp_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
......@@ -234,6 +261,14 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
config.driver_data = micsupp;
config.regmap = arizona->regmap;
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_micsupp_of_get_pdata(arizona, &config);
if (ret < 0)
return ret;
}
}
if (arizona->pdata.micvdd)
config.init_data = arizona->pdata.micvdd;
else
......@@ -253,6 +288,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
return ret;
}
of_node_put(config.of_node);
platform_set_drvdata(pdev, micsupp);
return 0;
......
/*
* max14577.c - Regulator driver for the Maxim 14577
* max14577.c - Regulator driver for the Maxim 14577/77836
*
* Copyright (C) 2013,2014 Samsung Electronics
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
......@@ -22,6 +22,42 @@
#include <linux/mfd/max14577-private.h>
#include <linux/regulator/of_regulator.h>
/*
* Valid limits of current for max14577 and max77836 chargers.
* They must correspond to MBCICHWRCL and MBCICHWRCH fields in CHGCTRL4
* register for given chipset.
*/
struct maxim_charger_current {
/* Minimal current, set in CHGCTRL4/MBCICHWRCL, uA */
unsigned int min;
/*
* Minimal current when high setting is active,
* set in CHGCTRL4/MBCICHWRCH, uA
*/
unsigned int high_start;
/* Value of one step in high setting, uA */
unsigned int high_step;
/* Maximum current of high setting, uA */
unsigned int max;
};
/* Table of valid charger currents for different Maxim chipsets */
static const struct maxim_charger_current maxim_charger_currents[] = {
[MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 },
[MAXIM_DEVICE_TYPE_MAX14577] = {
.min = MAX14577_REGULATOR_CURRENT_LIMIT_MIN,
.high_start = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START,
.high_step = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
.max = MAX14577_REGULATOR_CURRENT_LIMIT_MAX,
},
[MAXIM_DEVICE_TYPE_MAX77836] = {
.min = MAX77836_REGULATOR_CURRENT_LIMIT_MIN,
.high_start = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START,
.high_step = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
.max = MAX77836_REGULATOR_CURRENT_LIMIT_MAX,
},
};
static int max14577_reg_is_enabled(struct regulator_dev *rdev)
{
int rid = rdev_get_id(rdev);
......@@ -47,6 +83,9 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
{
u8 reg_data;
struct regmap *rmap = rdev->regmap;
struct max14577 *max14577 = rdev_get_drvdata(rdev);
const struct maxim_charger_current *limits =
&maxim_charger_currents[max14577->dev_type];
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
......@@ -54,12 +93,11 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, &reg_data);
if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
return MAX14577_REGULATOR_CURRENT_LIMIT_MIN;
return limits->min;
reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >>
CHGCTRL4_MBCICHWRCH_SHIFT);
return MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
reg_data * MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP;
return limits->high_start + reg_data * limits->high_step;
}
static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
......@@ -67,33 +105,39 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
{
int i, current_bits = 0xf;
u8 reg_data;
struct max14577 *max14577 = rdev_get_drvdata(rdev);
const struct maxim_charger_current *limits =
&maxim_charger_currents[max14577->dev_type];
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
if (min_uA > MAX14577_REGULATOR_CURRENT_LIMIT_MAX ||
max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_MIN)
if (min_uA > limits->max || max_uA < limits->min)
return -EINVAL;
if (max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START) {
/* Less than 200 mA, so set 90mA (turn only Low Bit off) */
if (max_uA < limits->high_start) {
/*
* Less than high_start,
* so set the minimal current (turn only Low Bit off)
*/
u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT;
return max14577_update_reg(rdev->regmap,
MAX14577_CHG_REG_CHG_CTRL4,
CHGCTRL4_MBCICHWRCL_MASK, reg_data);
}
/* max_uA is in range: <LIMIT_HIGH_START, inifinite>, so search for
* valid current starting from LIMIT_MAX. */
for (i = MAX14577_REGULATOR_CURRENT_LIMIT_MAX;
i >= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START;
i -= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP) {
/*
* max_uA is in range: <high_start, inifinite>, so search for
* valid current starting from maximum current.
*/
for (i = limits->max; i >= limits->high_start; i -= limits->high_step) {
if (i <= max_uA)
break;
current_bits--;
}
BUG_ON(current_bits < 0); /* Cannot happen */
/* Turn Low Bit on (use range 200mA-950 mA) */
/* Turn Low Bit on (use range high_start-max)... */
reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
/* and set proper High Bits */
reg_data |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT;
......@@ -118,7 +162,7 @@ static struct regulator_ops max14577_charger_ops = {
.set_current_limit = max14577_reg_set_current_limit,
};
static const struct regulator_desc supported_regulators[] = {
static const struct regulator_desc max14577_supported_regulators[] = {
[MAX14577_SAFEOUT] = {
.name = "SAFEOUT",
.id = MAX14577_SAFEOUT,
......@@ -141,16 +185,88 @@ static const struct regulator_desc supported_regulators[] = {
},
};
static struct regulator_ops max77836_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
/* TODO: add .set_suspend_mode */
};
static const struct regulator_desc max77836_supported_regulators[] = {
[MAX14577_SAFEOUT] = {
.name = "SAFEOUT",
.id = MAX14577_SAFEOUT,
.ops = &max14577_safeout_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.n_voltages = 1,
.min_uV = MAX14577_REGULATOR_SAFEOUT_VOLTAGE,
.enable_reg = MAX14577_REG_CONTROL2,
.enable_mask = CTRL2_SFOUTORD_MASK,
},
[MAX14577_CHARGER] = {
.name = "CHARGER",
.id = MAX14577_CHARGER,
.ops = &max14577_charger_ops,
.type = REGULATOR_CURRENT,
.owner = THIS_MODULE,
.enable_reg = MAX14577_CHG_REG_CHG_CTRL2,
.enable_mask = CHGCTRL2_MBCHOSTEN_MASK,
},
[MAX77836_LDO1] = {
.name = "LDO1",
.id = MAX77836_LDO1,
.ops = &max77836_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
.min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
.uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
.enable_reg = MAX77836_LDO_REG_CNFG1_LDO1,
.enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
.vsel_reg = MAX77836_LDO_REG_CNFG1_LDO1,
.vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
},
[MAX77836_LDO2] = {
.name = "LDO2",
.id = MAX77836_LDO2,
.ops = &max77836_ldo_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
.min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
.uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
.enable_reg = MAX77836_LDO_REG_CNFG1_LDO2,
.enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
.vsel_reg = MAX77836_LDO_REG_CNFG1_LDO2,
.vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
},
};
#ifdef CONFIG_OF
static struct of_regulator_match max14577_regulator_matches[] = {
{ .name = "SAFEOUT", },
{ .name = "CHARGER", },
};
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
static struct of_regulator_match max77836_regulator_matches[] = {
{ .name = "SAFEOUT", },
{ .name = "CHARGER", },
{ .name = "LDO1", },
{ .name = "LDO2", },
};
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
enum maxim_device_type dev_type)
{
int ret;
struct device_node *np;
struct of_regulator_match *regulator_matches;
unsigned int regulator_matches_size;
np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!np) {
......@@ -158,8 +274,19 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
return -EINVAL;
}
ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
MAX14577_REG_MAX);
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
regulator_matches = max77836_regulator_matches;
regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
regulator_matches = max14577_regulator_matches;
regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches);
}
ret = of_regulator_match(&pdev->dev, np, regulator_matches,
regulator_matches_size);
if (ret < 0)
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
else
......@@ -170,31 +297,74 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
return ret;
}
static inline struct regulator_init_data *match_init_data(int index)
static inline struct regulator_init_data *match_init_data(int index,
enum maxim_device_type dev_type)
{
return max14577_regulator_matches[index].init_data;
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
return max77836_regulator_matches[index].init_data;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
return max14577_regulator_matches[index].init_data;
}
}
static inline struct device_node *match_of_node(int index)
static inline struct device_node *match_of_node(int index,
enum maxim_device_type dev_type)
{
return max14577_regulator_matches[index].of_node;
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
return max77836_regulator_matches[index].of_node;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
return max14577_regulator_matches[index].of_node;
}
}
#else /* CONFIG_OF */
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
enum maxim_device_type dev_type)
{
return 0;
}
static inline struct regulator_init_data *match_init_data(int index)
static inline struct regulator_init_data *match_init_data(int index,
enum maxim_device_type dev_type)
{
return NULL;
}
static inline struct device_node *match_of_node(int index)
static inline struct device_node *match_of_node(int index,
enum maxim_device_type dev_type)
{
return NULL;
}
#endif /* CONFIG_OF */
/**
* Registers for regulators of max77836 use different I2C slave addresses so
* different regmaps must be used for them.
*
* Returns proper regmap for accessing regulator passed by id.
*/
static struct regmap *max14577_get_regmap(struct max14577 *max14577,
int reg_id)
{
switch (max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
switch (reg_id) {
case MAX77836_SAFEOUT ... MAX77836_CHARGER:
return max14577->regmap;
default:
/* MAX77836_LDO1 ... MAX77836_LDO2 */
return max14577->regmap_pmic;
}
case MAXIM_DEVICE_TYPE_MAX14577:
default:
return max14577->regmap;
}
}
static int max14577_regulator_probe(struct platform_device *pdev)
{
......@@ -202,15 +372,29 @@ static int max14577_regulator_probe(struct platform_device *pdev)
struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
int i, ret;
struct regulator_config config = {};
const struct regulator_desc *supported_regulators;
unsigned int supported_regulators_size;
enum maxim_device_type dev_type = max14577->dev_type;
ret = max14577_regulator_dt_parse_pdata(pdev);
ret = max14577_regulator_dt_parse_pdata(pdev, dev_type);
if (ret)
return ret;
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
supported_regulators = max77836_supported_regulators;
supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators);
break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
supported_regulators = max14577_supported_regulators;
supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators);
}
config.dev = &pdev->dev;
config.regmap = max14577->regmap;
config.driver_data = max14577;
for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
for (i = 0; i < supported_regulators_size; i++) {
struct regulator_dev *regulator;
/*
* Index of supported_regulators[] is also the id and must
......@@ -220,17 +404,19 @@ static int max14577_regulator_probe(struct platform_device *pdev)
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].of_node;
} else {
config.init_data = match_init_data(i);
config.of_node = match_of_node(i);
config.init_data = match_init_data(i, dev_type);
config.of_node = match_of_node(i, dev_type);
}
config.regmap = max14577_get_regmap(max14577,
supported_regulators[i].id);
regulator = devm_regulator_register(&pdev->dev,
&supported_regulators[i], &config);
if (IS_ERR(regulator)) {
ret = PTR_ERR(regulator);
dev_err(&pdev->dev,
"Regulator init failed for ID %d with error: %d\n",
i, ret);
"Regulator init failed for %d/%s with error: %d\n",
i, supported_regulators[i].name, ret);
return ret;
}
}
......@@ -238,20 +424,41 @@ static int max14577_regulator_probe(struct platform_device *pdev)
return ret;
}
static const struct platform_device_id max14577_regulator_id[] = {
{ "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, },
{ "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, },
{ }
};
MODULE_DEVICE_TABLE(platform, max14577_regulator_id);
static struct platform_driver max14577_regulator_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "max14577-regulator",
},
.probe = max14577_regulator_probe,
.probe = max14577_regulator_probe,
.id_table = max14577_regulator_id,
};
static int __init max14577_regulator_init(void)
{
/* Check for valid values for charger */
BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
MAX14577_REGULATOR_CURRENT_LIMIT_MAX);
BUILD_BUG_ON(ARRAY_SIZE(supported_regulators) != MAX14577_REG_MAX);
BUILD_BUG_ON(MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START +
MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
MAX77836_REGULATOR_CURRENT_LIMIT_MAX);
/* Valid charger current values must be provided for each chipset */
BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM);
BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM);
BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM);
BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN +
(MAX77836_REGULATOR_LDO_VOLTAGE_STEP *
(MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) !=
MAX77836_REGULATOR_LDO_VOLTAGE_MAX);
return platform_driver_register(&max14577_regulator_driver);
}
......@@ -264,6 +471,6 @@ static void __exit max14577_regulator_exit(void)
module_exit(max14577_regulator_exit);
MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
MODULE_DESCRIPTION("MAXIM 14577 regulator driver");
MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:max14577-regulator");
......@@ -68,7 +68,7 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
return rdev_get_dev(rdev)->parent;
}
static struct regulator_ops tps6586x_regulator_ops = {
static struct regulator_ops tps6586x_rw_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
......@@ -79,6 +79,16 @@ static struct regulator_ops tps6586x_regulator_ops = {
.disable = regulator_disable_regmap,
};
static struct regulator_ops tps6586x_ro_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
};
static struct regulator_ops tps6586x_sys_regulator_ops = {
};
......@@ -106,6 +116,13 @@ static const unsigned int tps6586x_sm2_voltages[] = {
4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000,
};
static int tps658640_sm2_voltages[] = {
2150000, 2200000, 2250000, 2300000, 2350000, 2400000, 2450000, 2500000,
2550000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000, 2900000,
2950000, 3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000,
3350000, 3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000,
};
static const unsigned int tps658643_sm2_voltages[] = {
1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000,
1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000,
......@@ -120,12 +137,16 @@ static const unsigned int tps6586x_dvm_voltages[] = {
1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
};
#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \
static int tps658640_rtc_voltages[] = {
2500000, 2850000, 3100000, 3300000,
};
#define TPS6586X_REGULATOR(_id, _ops, _pin_name, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
.desc = { \
.supply_name = _pin_name, \
.name = "REG-" #_id, \
.ops = &tps6586x_regulator_ops, \
.ops = &tps6586x_## _ops ## _regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = TPS6586X_ID_##_id, \
.n_voltages = ARRAY_SIZE(vdata##_voltages), \
......@@ -146,14 +167,21 @@ static const unsigned int tps6586x_dvm_voltages[] = {
#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, 0, 0) \
}
#define TPS6586X_FIXED_LDO(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
TPS6586X_REGULATOR(_id, ro, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, 0, 0) \
}
#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
{ \
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
}
......@@ -207,6 +235,26 @@ static struct tps6586x_regulator tps658623_regulator[] = {
END, 7),
};
static struct tps6586x_regulator tps658640_regulator[] = {
TPS6586X_LDO(LDO_3, "vinldo23", tps6586x_ldo0, SUPPLYV4, 0, 3,
ENC, 2, END, 2),
TPS6586X_LDO(LDO_5, "REG-SYS", tps6586x_ldo0, SUPPLYV6, 0, 3,
ENE, 6, ENE, 6),
TPS6586X_LDO(LDO_6, "vinldo678", tps6586x_ldo0, SUPPLYV3, 0, 3,
ENC, 4, END, 4),
TPS6586X_LDO(LDO_7, "vinldo678", tps6586x_ldo0, SUPPLYV3, 3, 3,
ENC, 5, END, 5),
TPS6586X_LDO(LDO_8, "vinldo678", tps6586x_ldo0, SUPPLYV2, 5, 3,
ENC, 6, END, 6),
TPS6586X_LDO(LDO_9, "vinldo9", tps6586x_ldo0, SUPPLYV6, 3, 3,
ENE, 7, ENE, 7),
TPS6586X_LDO(SM_2, "vin-sm2", tps658640_sm2, SUPPLYV2, 0, 5,
ENC, 7, END, 7),
TPS6586X_FIXED_LDO(LDO_RTC, "REG-SYS", tps658640_rtc, SUPPLYV4, 3, 2,
V4, 7, V4, 7),
};
static struct tps6586x_regulator tps658643_regulator[] = {
TPS6586X_LDO(SM_2, "vin-sm2", tps658643_sm2, SUPPLYV2, 0, 5, ENC, 7,
END, 7),
......@@ -295,6 +343,11 @@ static struct tps6586x_regulator *find_regulator_info(int id, int version)
table = tps658623_regulator;
num = ARRAY_SIZE(tps658623_regulator);
break;
case TPS658640:
case TPS658640v2:
table = tps658640_regulator;
num = ARRAY_SIZE(tps658640_regulator);
break;
case TPS658643:
table = tps658643_regulator;
num = ARRAY_SIZE(tps658643_regulator);
......
......@@ -468,6 +468,27 @@ struct cpufreq_frequency_table {
* order */
};
bool cpufreq_next_valid(struct cpufreq_frequency_table **pos);
/*
* cpufreq_for_each_entry - iterate over a cpufreq_frequency_table
* @pos: the cpufreq_frequency_table * to use as a loop cursor.
* @table: the cpufreq_frequency_table * to iterate over.
*/
#define cpufreq_for_each_entry(pos, table) \
for (pos = table; pos->frequency != CPUFREQ_TABLE_END; pos++)
/*
* cpufreq_for_each_valid_entry - iterate over a cpufreq_frequency_table
* excluding CPUFREQ_ENTRY_INVALID frequencies.
* @pos: the cpufreq_frequency_table * to use as a loop cursor.
* @table: the cpufreq_frequency_table * to iterate over.
*/
#define cpufreq_for_each_valid_entry(pos, table) \
for (pos = table; cpufreq_next_valid(&pos); pos++)
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table);
......
......@@ -124,4 +124,7 @@ int wm5102_patch(struct arizona *arizona);
int wm5110_patch(struct arizona *arizona);
int wm8997_patch(struct arizona *arizona);
extern int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
bool mandatory);
#endif
/*
* max14577-private.h - Common API for the Maxim 14577 internal sub chip
* max14577-private.h - Common API for the Maxim 14577/77836 internal sub chip
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
......@@ -22,9 +22,19 @@
#include <linux/i2c.h>
#include <linux/regmap.h>
#define MAX14577_REG_INVALID (0xff)
#define I2C_ADDR_PMIC (0x46 >> 1)
#define I2C_ADDR_MUIC (0x4A >> 1)
#define I2C_ADDR_FG (0x6C >> 1)
/* Slave addr = 0x4A: Interrupt */
enum maxim_device_type {
MAXIM_DEVICE_TYPE_UNKNOWN = 0,
MAXIM_DEVICE_TYPE_MAX14577,
MAXIM_DEVICE_TYPE_MAX77836,
MAXIM_DEVICE_TYPE_NUM,
};
/* Slave addr = 0x4A: MUIC and Charger */
enum max14577_reg {
MAX14577_REG_DEVICEID = 0x00,
MAX14577_REG_INT1 = 0x01,
......@@ -74,20 +84,22 @@ enum max14577_muic_charger_type {
};
/* MAX14577 interrupts */
#define INT1_ADC_MASK (0x1 << 0)
#define INT1_ADCLOW_MASK (0x1 << 1)
#define INT1_ADCERR_MASK (0x1 << 2)
#define INT2_CHGTYP_MASK (0x1 << 0)
#define INT2_CHGDETRUN_MASK (0x1 << 1)
#define INT2_DCDTMR_MASK (0x1 << 2)
#define INT2_DBCHG_MASK (0x1 << 3)
#define INT2_VBVOLT_MASK (0x1 << 4)
#define INT3_EOC_MASK (0x1 << 0)
#define INT3_CGMBC_MASK (0x1 << 1)
#define INT3_OVP_MASK (0x1 << 2)
#define INT3_MBCCHGERR_MASK (0x1 << 3)
#define MAX14577_INT1_ADC_MASK BIT(0)
#define MAX14577_INT1_ADCLOW_MASK BIT(1)
#define MAX14577_INT1_ADCERR_MASK BIT(2)
#define MAX77836_INT1_ADC1K_MASK BIT(3)
#define MAX14577_INT2_CHGTYP_MASK BIT(0)
#define MAX14577_INT2_CHGDETRUN_MASK BIT(1)
#define MAX14577_INT2_DCDTMR_MASK BIT(2)
#define MAX14577_INT2_DBCHG_MASK BIT(3)
#define MAX14577_INT2_VBVOLT_MASK BIT(4)
#define MAX77836_INT2_VIDRM_MASK BIT(5)
#define MAX14577_INT3_EOC_MASK BIT(0)
#define MAX14577_INT3_CGMBC_MASK BIT(1)
#define MAX14577_INT3_OVP_MASK BIT(2)
#define MAX14577_INT3_MBCCHGERR_MASK BIT(3)
/* MAX14577 DEVICE ID register */
#define DEVID_VENDORID_SHIFT 0
......@@ -99,9 +111,11 @@ enum max14577_muic_charger_type {
#define STATUS1_ADC_SHIFT 0
#define STATUS1_ADCLOW_SHIFT 5
#define STATUS1_ADCERR_SHIFT 6
#define MAX77836_STATUS1_ADC1K_SHIFT 7
#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT)
#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT)
#define STATUS1_ADCLOW_MASK BIT(STATUS1_ADCLOW_SHIFT)
#define STATUS1_ADCERR_MASK BIT(STATUS1_ADCERR_SHIFT)
#define MAX77836_STATUS1_ADC1K_MASK BIT(MAX77836_STATUS1_ADC1K_SHIFT)
/* MAX14577 STATUS2 register */
#define STATUS2_CHGTYP_SHIFT 0
......@@ -109,11 +123,13 @@ enum max14577_muic_charger_type {
#define STATUS2_DCDTMR_SHIFT 4
#define STATUS2_DBCHG_SHIFT 5
#define STATUS2_VBVOLT_SHIFT 6
#define MAX77836_STATUS2_VIDRM_SHIFT 7
#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT)
#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT)
#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT)
#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT)
#define STATUS2_CHGDETRUN_MASK BIT(STATUS2_CHGDETRUN_SHIFT)
#define STATUS2_DCDTMR_MASK BIT(STATUS2_DCDTMR_SHIFT)
#define STATUS2_DBCHG_MASK BIT(STATUS2_DBCHG_SHIFT)
#define STATUS2_VBVOLT_MASK BIT(STATUS2_VBVOLT_SHIFT)
#define MAX77836_STATUS2_VIDRM_MASK BIT(MAX77836_STATUS2_VIDRM_SHIFT)
/* MAX14577 CONTROL1 register */
#define COMN1SW_SHIFT 0
......@@ -122,8 +138,8 @@ enum max14577_muic_charger_type {
#define IDBEN_SHIFT 7
#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
#define MICEN_MASK (0x1 << MICEN_SHIFT)
#define IDBEN_MASK (0x1 << IDBEN_SHIFT)
#define MICEN_MASK BIT(MICEN_SHIFT)
#define IDBEN_MASK BIT(IDBEN_SHIFT)
#define CLEAR_IDBEN_MICEN_MASK (COMN1SW_MASK | COMP2SW_MASK)
#define CTRL1_SW_USB ((1 << COMP2SW_SHIFT) \
| (1 << COMN1SW_SHIFT))
......@@ -143,14 +159,14 @@ enum max14577_muic_charger_type {
#define CTRL2_ACCDET_SHIFT (5)
#define CTRL2_USBCPINT_SHIFT (6)
#define CTRL2_RCPS_SHIFT (7)
#define CTRL2_LOWPWR_MASK (0x1 << CTRL2_LOWPWR_SHIFT)
#define CTRL2_ADCEN_MASK (0x1 << CTRL2_ADCEN_SHIFT)
#define CTRL2_CPEN_MASK (0x1 << CTRL2_CPEN_SHIFT)
#define CTRL2_SFOUTASRT_MASK (0x1 << CTRL2_SFOUTASRT_SHIFT)
#define CTRL2_SFOUTORD_MASK (0x1 << CTRL2_SFOUTORD_SHIFT)
#define CTRL2_ACCDET_MASK (0x1 << CTRL2_ACCDET_SHIFT)
#define CTRL2_USBCPINT_MASK (0x1 << CTRL2_USBCPINT_SHIFT)
#define CTRL2_RCPS_MASK (0x1 << CTR2_RCPS_SHIFT)
#define CTRL2_LOWPWR_MASK BIT(CTRL2_LOWPWR_SHIFT)
#define CTRL2_ADCEN_MASK BIT(CTRL2_ADCEN_SHIFT)
#define CTRL2_CPEN_MASK BIT(CTRL2_CPEN_SHIFT)
#define CTRL2_SFOUTASRT_MASK BIT(CTRL2_SFOUTASRT_SHIFT)
#define CTRL2_SFOUTORD_MASK BIT(CTRL2_SFOUTORD_SHIFT)
#define CTRL2_ACCDET_MASK BIT(CTRL2_ACCDET_SHIFT)
#define CTRL2_USBCPINT_MASK BIT(CTRL2_USBCPINT_SHIFT)
#define CTRL2_RCPS_MASK BIT(CTRL2_RCPS_SHIFT)
#define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \
(0 << CTRL2_LOWPWR_SHIFT))
......@@ -198,14 +214,14 @@ enum max14577_charger_reg {
#define CDETCTRL1_DBEXIT_SHIFT 5
#define CDETCTRL1_DBIDLE_SHIFT 6
#define CDETCTRL1_CDPDET_SHIFT 7
#define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT)
#define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT)
#define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT)
#define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT)
#define CDETCTRL1_DCHKTM_MASK (0x1 << CDETCTRL1_DCHKTM_SHIFT)
#define CDETCTRL1_DBEXIT_MASK (0x1 << CDETCTRL1_DBEXIT_SHIFT)
#define CDETCTRL1_DBIDLE_MASK (0x1 << CDETCTRL1_DBIDLE_SHIFT)
#define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT)
#define CDETCTRL1_CHGDETEN_MASK BIT(CDETCTRL1_CHGDETEN_SHIFT)
#define CDETCTRL1_CHGTYPMAN_MASK BIT(CDETCTRL1_CHGTYPMAN_SHIFT)
#define CDETCTRL1_DCDEN_MASK BIT(CDETCTRL1_DCDEN_SHIFT)
#define CDETCTRL1_DCD2SCT_MASK BIT(CDETCTRL1_DCD2SCT_SHIFT)
#define CDETCTRL1_DCHKTM_MASK BIT(CDETCTRL1_DCHKTM_SHIFT)
#define CDETCTRL1_DBEXIT_MASK BIT(CDETCTRL1_DBEXIT_SHIFT)
#define CDETCTRL1_DBIDLE_MASK BIT(CDETCTRL1_DBIDLE_SHIFT)
#define CDETCTRL1_CDPDET_MASK BIT(CDETCTRL1_CDPDET_SHIFT)
/* MAX14577 CHGCTRL1 register */
#define CHGCTRL1_TCHW_SHIFT 4
......@@ -213,9 +229,9 @@ enum max14577_charger_reg {
/* MAX14577 CHGCTRL2 register */
#define CHGCTRL2_MBCHOSTEN_SHIFT 6
#define CHGCTRL2_MBCHOSTEN_MASK (0x1 << CHGCTRL2_MBCHOSTEN_SHIFT)
#define CHGCTRL2_MBCHOSTEN_MASK BIT(CHGCTRL2_MBCHOSTEN_SHIFT)
#define CHGCTRL2_VCHGR_RC_SHIFT 7
#define CHGCTRL2_VCHGR_RC_MASK (0x1 << CHGCTRL2_VCHGR_RC_SHIFT)
#define CHGCTRL2_VCHGR_RC_MASK BIT(CHGCTRL2_VCHGR_RC_SHIFT)
/* MAX14577 CHGCTRL3 register */
#define CHGCTRL3_MBCCVWRC_SHIFT 0
......@@ -225,7 +241,7 @@ enum max14577_charger_reg {
#define CHGCTRL4_MBCICHWRCH_SHIFT 0
#define CHGCTRL4_MBCICHWRCH_MASK (0xf << CHGCTRL4_MBCICHWRCH_SHIFT)
#define CHGCTRL4_MBCICHWRCL_SHIFT 4
#define CHGCTRL4_MBCICHWRCL_MASK (0x1 << CHGCTRL4_MBCICHWRCL_SHIFT)
#define CHGCTRL4_MBCICHWRCL_MASK BIT(CHGCTRL4_MBCICHWRCL_SHIFT)
/* MAX14577 CHGCTRL5 register */
#define CHGCTRL5_EOCS_SHIFT 0
......@@ -233,7 +249,7 @@ enum max14577_charger_reg {
/* MAX14577 CHGCTRL6 register */
#define CHGCTRL6_AUTOSTOP_SHIFT 5
#define CHGCTRL6_AUTOSTOP_MASK (0x1 << CHGCTRL6_AUTOSTOP_SHIFT)
#define CHGCTRL6_AUTOSTOP_MASK BIT(CHGCTRL6_AUTOSTOP_SHIFT)
/* MAX14577 CHGCTRL7 register */
#define CHGCTRL7_OTPCGHCVS_SHIFT 0
......@@ -245,14 +261,111 @@ enum max14577_charger_reg {
#define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP 50000
#define MAX14577_REGULATOR_CURRENT_LIMIT_MAX 950000
/* MAX77836 regulator current limits (as in CHGCTRL4 register), uA */
#define MAX77836_REGULATOR_CURRENT_LIMIT_MIN 45000
#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START 100000
#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP 25000
#define MAX77836_REGULATOR_CURRENT_LIMIT_MAX 475000
/* MAX14577 regulator SFOUT LDO voltage, fixed, uV */
#define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000
/* MAX77836 regulator LDOx voltage, uV */
#define MAX77836_REGULATOR_LDO_VOLTAGE_MIN 800000
#define MAX77836_REGULATOR_LDO_VOLTAGE_MAX 3950000
#define MAX77836_REGULATOR_LDO_VOLTAGE_STEP 50000
#define MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM 64
/* Slave addr = 0x46: PMIC */
enum max77836_pmic_reg {
MAX77836_PMIC_REG_PMIC_ID = 0x20,
MAX77836_PMIC_REG_PMIC_REV = 0x21,
MAX77836_PMIC_REG_INTSRC = 0x22,
MAX77836_PMIC_REG_INTSRC_MASK = 0x23,
MAX77836_PMIC_REG_TOPSYS_INT = 0x24,
MAX77836_PMIC_REG_TOPSYS_INT_MASK = 0x26,
MAX77836_PMIC_REG_TOPSYS_STAT = 0x28,
MAX77836_PMIC_REG_MRSTB_CNTL = 0x2A,
MAX77836_PMIC_REG_LSCNFG = 0x2B,
MAX77836_LDO_REG_CNFG1_LDO1 = 0x51,
MAX77836_LDO_REG_CNFG2_LDO1 = 0x52,
MAX77836_LDO_REG_CNFG1_LDO2 = 0x53,
MAX77836_LDO_REG_CNFG2_LDO2 = 0x54,
MAX77836_LDO_REG_CNFG_LDO_BIAS = 0x55,
MAX77836_COMP_REG_COMP1 = 0x60,
MAX77836_PMIC_REG_END,
};
#define MAX77836_INTSRC_MASK_TOP_INT_SHIFT 1
#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT 3
#define MAX77836_INTSRC_MASK_TOP_INT_MASK BIT(MAX77836_INTSRC_MASK_TOP_INT_SHIFT)
#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK BIT(MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT)
/* MAX77836 PMIC interrupts */
#define MAX77836_TOPSYS_INT_T120C_SHIFT 0
#define MAX77836_TOPSYS_INT_T140C_SHIFT 1
#define MAX77836_TOPSYS_INT_T120C_MASK BIT(MAX77836_TOPSYS_INT_T120C_SHIFT)
#define MAX77836_TOPSYS_INT_T140C_MASK BIT(MAX77836_TOPSYS_INT_T140C_SHIFT)
/* LDO1/LDO2 CONFIG1 register */
#define MAX77836_CNFG1_LDO_PWRMD_SHIFT 6
#define MAX77836_CNFG1_LDO_TV_SHIFT 0
#define MAX77836_CNFG1_LDO_PWRMD_MASK (0x3 << MAX77836_CNFG1_LDO_PWRMD_SHIFT)
#define MAX77836_CNFG1_LDO_TV_MASK (0x3f << MAX77836_CNFG1_LDO_TV_SHIFT)
/* LDO1/LDO2 CONFIG2 register */
#define MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT 7
#define MAX77836_CNFG2_LDO_ALPMEN_SHIFT 6
#define MAX77836_CNFG2_LDO_COMP_SHIFT 4
#define MAX77836_CNFG2_LDO_POK_SHIFT 3
#define MAX77836_CNFG2_LDO_ADE_SHIFT 1
#define MAX77836_CNFG2_LDO_SS_SHIFT 0
#define MAX77836_CNFG2_LDO_OVCLMPEN_MASK BIT(MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT)
#define MAX77836_CNFG2_LDO_ALPMEN_MASK BIT(MAX77836_CNFG2_LDO_ALPMEN_SHIFT)
#define MAX77836_CNFG2_LDO_COMP_MASK (0x3 << MAX77836_CNFG2_LDO_COMP_SHIFT)
#define MAX77836_CNFG2_LDO_POK_MASK BIT(MAX77836_CNFG2_LDO_POK_SHIFT)
#define MAX77836_CNFG2_LDO_ADE_MASK BIT(MAX77836_CNFG2_LDO_ADE_SHIFT)
#define MAX77836_CNFG2_LDO_SS_MASK BIT(MAX77836_CNFG2_LDO_SS_SHIFT)
/* Slave addr = 0x6C: Fuel-Gauge/Battery */
enum max77836_fg_reg {
MAX77836_FG_REG_VCELL_MSB = 0x02,
MAX77836_FG_REG_VCELL_LSB = 0x03,
MAX77836_FG_REG_SOC_MSB = 0x04,
MAX77836_FG_REG_SOC_LSB = 0x05,
MAX77836_FG_REG_MODE_H = 0x06,
MAX77836_FG_REG_MODE_L = 0x07,
MAX77836_FG_REG_VERSION_MSB = 0x08,
MAX77836_FG_REG_VERSION_LSB = 0x09,
MAX77836_FG_REG_HIBRT_H = 0x0A,
MAX77836_FG_REG_HIBRT_L = 0x0B,
MAX77836_FG_REG_CONFIG_H = 0x0C,
MAX77836_FG_REG_CONFIG_L = 0x0D,
MAX77836_FG_REG_VALRT_MIN = 0x14,
MAX77836_FG_REG_VALRT_MAX = 0x15,
MAX77836_FG_REG_CRATE_MSB = 0x16,
MAX77836_FG_REG_CRATE_LSB = 0x17,
MAX77836_FG_REG_VRESET = 0x18,
MAX77836_FG_REG_FGID = 0x19,
MAX77836_FG_REG_STATUS_H = 0x1A,
MAX77836_FG_REG_STATUS_L = 0x1B,
/*
* TODO: TABLE registers
* TODO: CMD register
*/
MAX77836_FG_REG_END,
};
enum max14577_irq {
/* INT1 */
MAX14577_IRQ_INT1_ADC,
MAX14577_IRQ_INT1_ADCLOW,
MAX14577_IRQ_INT1_ADCERR,
MAX77836_IRQ_INT1_ADC1K,
/* INT2 */
MAX14577_IRQ_INT2_CHGTYP,
......@@ -260,6 +373,7 @@ enum max14577_irq {
MAX14577_IRQ_INT2_DCDTMR,
MAX14577_IRQ_INT2_DBCHG,
MAX14577_IRQ_INT2_VBVOLT,
MAX77836_IRQ_INT2_VIDRM,
/* INT3 */
MAX14577_IRQ_INT3_EOC,
......@@ -267,21 +381,25 @@ enum max14577_irq {
MAX14577_IRQ_INT3_OVP,
MAX14577_IRQ_INT3_MBCCHGERR,
/* TOPSYS_INT, only MAX77836 */
MAX77836_IRQ_TOPSYS_T140C,
MAX77836_IRQ_TOPSYS_T120C,
MAX14577_IRQ_NUM,
};
struct max14577 {
struct device *dev;
struct i2c_client *i2c; /* Slave addr = 0x4A */
struct i2c_client *i2c_pmic; /* Slave addr = 0x46 */
enum maxim_device_type dev_type;
struct regmap *regmap;
struct regmap *regmap; /* For MUIC and Charger */
struct regmap *regmap_pmic;
struct regmap_irq_chip_data *irq_data;
struct regmap_irq_chip_data *irq_data; /* For MUIC and Charger */
struct regmap_irq_chip_data *irq_data_pmic;
int irq;
/* Device ID */
u8 vendor_id; /* Vendor Identification */
u8 device_id; /* Chip Version */
};
/* MAX14577 shared regmap API function */
......
/*
* max14577.h - Driver for the Maxim 14577
* max14577.h - Driver for the Maxim 14577/77836
*
* Copyright (C) 2013 Samsung Electrnoics
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
......@@ -20,6 +20,9 @@
* MAX14577 has MUIC, Charger devices.
* The devices share the same I2C bus and interrupt line
* included in this mfd driver.
*
* MAX77836 has additional PMIC and Fuel-Gauge on different I2C slave
* addresses.
*/
#ifndef __MAX14577_H__
......@@ -32,7 +35,17 @@ enum max14577_regulators {
MAX14577_SAFEOUT = 0,
MAX14577_CHARGER,
MAX14577_REG_MAX,
MAX14577_REGULATOR_NUM,
};
/* MAX77836 regulator IDs */
enum max77836_regulators {
MAX77836_SAFEOUT = 0,
MAX77836_CHARGER,
MAX77836_LDO1,
MAX77836_LDO2,
MAX77836_REGULATOR_NUM,
};
struct max14577_regulator_platform_data {
......
......@@ -11,6 +11,7 @@
#include <linux/mutex.h>
struct device;
struct regulator;
enum stmpe_block {
STMPE_BLOCK_GPIO = 1 << 0,
......@@ -62,6 +63,8 @@ struct stmpe_client_info;
/**
* struct stmpe - STMPE MFD structure
* @vcc: optional VCC regulator
* @vio: optional VIO regulator
* @lock: lock protecting I/O operations
* @irq_lock: IRQ bus lock
* @dev: device, mostly for dev_dbg()
......@@ -73,13 +76,14 @@ struct stmpe_client_info;
* @regs: list of addresses of registers which are at different addresses on
* different variants. Indexed by one of STMPE_IDX_*.
* @irq: irq number for stmpe
* @irq_base: starting IRQ number for internal IRQs
* @num_gpios: number of gpios, differs for variants
* @ier: cache of IER registers for bus_lock
* @oldier: cache of IER registers for bus_lock
* @pdata: platform data
*/
struct stmpe {
struct regulator *vcc;
struct regulator *vio;
struct mutex lock;
struct mutex irq_lock;
struct device *dev;
......@@ -91,7 +95,6 @@ struct stmpe {
const u8 *regs;
int irq;
int irq_base;
int num_gpios;
u8 ier[2];
u8 oldier[2];
......@@ -132,8 +135,6 @@ struct stmpe_keypad_platform_data {
/**
* struct stmpe_gpio_platform_data - STMPE GPIO platform data
* @gpio_base: first gpio number assigned. A maximum of
* %STMPE_NR_GPIOS GPIOs will be allocated.
* @norequest_mask: bitmask specifying which GPIOs should _not_ be
* requestable due to different usage (e.g. touch, keypad)
* STMPE_GPIO_NOREQ_* macros can be used here.
......@@ -141,7 +142,6 @@ struct stmpe_keypad_platform_data {
* @remove: board specific remove callback
*/
struct stmpe_gpio_platform_data {
int gpio_base;
unsigned norequest_mask;
void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
void (*remove)(struct stmpe *stmpe, unsigned gpio_base);
......@@ -195,8 +195,6 @@ struct stmpe_ts_platform_data {
* @irq_trigger: IRQ trigger to use for the interrupt to the host
* @autosleep: bool to enable/disable stmpe autosleep
* @autosleep_timeout: inactivity timeout in milliseconds for autosleep
* @irq_base: base IRQ number. %STMPE_NR_IRQS irqs will be used, or
* %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
* @irq_over_gpio: true if gpio is used to get irq
* @irq_gpio: gpio number over which irq will be requested (significant only if
* irq_over_gpio is true)
......@@ -207,7 +205,6 @@ struct stmpe_ts_platform_data {
struct stmpe_platform_data {
int id;
unsigned int blocks;
int irq_base;
unsigned int irq_trigger;
bool autosleep;
bool irq_over_gpio;
......@@ -219,10 +216,4 @@ struct stmpe_platform_data {
struct stmpe_ts_platform_data *ts;
};
#define STMPE_NR_INTERNAL_IRQS 9
#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x))
#define STMPE_NR_GPIOS 24
#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS)
#endif
......@@ -64,6 +64,20 @@ enum {
TPS65090_REGULATOR_MAX,
};
/* Register addresses */
#define TPS65090_REG_INTR_STS 0x00
#define TPS65090_REG_INTR_STS2 0x01
#define TPS65090_REG_INTR_MASK 0x02
#define TPS65090_REG_INTR_MASK2 0x03
#define TPS65090_REG_CG_CTRL0 0x04
#define TPS65090_REG_CG_CTRL1 0x05
#define TPS65090_REG_CG_CTRL2 0x06
#define TPS65090_REG_CG_CTRL3 0x07
#define TPS65090_REG_CG_CTRL4 0x08
#define TPS65090_REG_CG_CTRL5 0x09
#define TPS65090_REG_CG_STATUS1 0x0a
#define TPS65090_REG_CG_STATUS2 0x0b
struct tps65090 {
struct device *dev;
struct regmap *rmap;
......
......@@ -17,6 +17,8 @@
#define TPS658621A 0x15
#define TPS658621CD 0x2c
#define TPS658623 0x1b
#define TPS658640 0x01
#define TPS658640v2 0x02
#define TPS658643 0x03
enum {
......
......@@ -22,6 +22,7 @@
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/mfd/mc13xxx.h>
#include <linux/slab.h>
#include <sound/core.h>
......@@ -750,6 +751,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
{
struct mc13783_priv *priv;
struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
struct device_node *np;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
......@@ -760,7 +762,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
priv->adc_ssi_port = pdata->adc_ssi_port;
priv->dac_ssi_port = pdata->dac_ssi_port;
} else {
return -ENOSYS;
np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
if (!np)
return -ENOSYS;
ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
if (ret)
return ret;
ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
if (ret)
return ret;
}
dev_set_drvdata(&pdev->dev, priv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment