Merge branches 'common/clkfwk', 'common/pfc' and 'common/serial-rework' into sh-latest
This commit is contained in:
@@ -355,7 +355,7 @@ static int clk_establish_mapping(struct clk *clk)
|
||||
*/
|
||||
if (!clk->parent) {
|
||||
clk->mapping = &dummy_mapping;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -384,6 +384,9 @@ static int clk_establish_mapping(struct clk *clk)
|
||||
}
|
||||
|
||||
clk->mapping = mapping;
|
||||
out:
|
||||
clk->mapped_reg = clk->mapping->base;
|
||||
clk->mapped_reg += (phys_addr_t)clk->enable_reg - clk->mapping->phys;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -402,10 +405,12 @@ static void clk_teardown_mapping(struct clk *clk)
|
||||
|
||||
/* Nothing to do */
|
||||
if (mapping == &dummy_mapping)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
kref_put(&mapping->ref, clk_destroy_mapping);
|
||||
clk->mapping = NULL;
|
||||
out:
|
||||
clk->mapped_reg = NULL;
|
||||
}
|
||||
|
||||
int clk_register(struct clk *clk)
|
||||
|
@@ -15,15 +15,15 @@
|
||||
|
||||
static int sh_clk_mstp32_enable(struct clk *clk)
|
||||
{
|
||||
__raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
|
||||
clk->enable_reg);
|
||||
iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
|
||||
clk->mapped_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_clk_mstp32_disable(struct clk *clk)
|
||||
{
|
||||
__raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
|
||||
clk->enable_reg);
|
||||
iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
|
||||
clk->mapped_reg);
|
||||
}
|
||||
|
||||
static struct clk_ops sh_clk_mstp32_clk_ops = {
|
||||
@@ -72,7 +72,7 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
|
||||
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
|
||||
table, NULL);
|
||||
|
||||
idx = __raw_readl(clk->enable_reg) & 0x003f;
|
||||
idx = ioread32(clk->mapped_reg) & 0x003f;
|
||||
|
||||
return clk->freq_table[idx].frequency;
|
||||
}
|
||||
@@ -98,10 +98,10 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value = __raw_readl(clk->enable_reg) &
|
||||
value = ioread32(clk->mapped_reg) &
|
||||
~(((1 << clk->src_width) - 1) << clk->src_shift);
|
||||
|
||||
__raw_writel(value | (i << clk->src_shift), clk->enable_reg);
|
||||
iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
|
||||
|
||||
/* Rebuild the frequency table */
|
||||
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
|
||||
@@ -119,10 +119,10 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
|
||||
if (idx < 0)
|
||||
return idx;
|
||||
|
||||
value = __raw_readl(clk->enable_reg);
|
||||
value = ioread32(clk->mapped_reg);
|
||||
value &= ~0x3f;
|
||||
value |= idx;
|
||||
__raw_writel(value, clk->enable_reg);
|
||||
iowrite32(value, clk->mapped_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -133,9 +133,9 @@ static int sh_clk_div6_enable(struct clk *clk)
|
||||
|
||||
ret = sh_clk_div6_set_rate(clk, clk->rate);
|
||||
if (ret == 0) {
|
||||
value = __raw_readl(clk->enable_reg);
|
||||
value = ioread32(clk->mapped_reg);
|
||||
value &= ~0x100; /* clear stop bit to enable clock */
|
||||
__raw_writel(value, clk->enable_reg);
|
||||
iowrite32(value, clk->mapped_reg);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -144,10 +144,10 @@ static void sh_clk_div6_disable(struct clk *clk)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
value = __raw_readl(clk->enable_reg);
|
||||
value = ioread32(clk->mapped_reg);
|
||||
value |= 0x100; /* stop clock */
|
||||
value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
|
||||
__raw_writel(value, clk->enable_reg);
|
||||
iowrite32(value, clk->mapped_reg);
|
||||
}
|
||||
|
||||
static struct clk_ops sh_clk_div6_clk_ops = {
|
||||
@@ -167,6 +167,38 @@ static struct clk_ops sh_clk_div6_reparent_clk_ops = {
|
||||
.set_parent = sh_clk_div6_set_parent,
|
||||
};
|
||||
|
||||
static int __init sh_clk_init_parent(struct clk *clk)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (clk->parent)
|
||||
return 0;
|
||||
|
||||
if (!clk->parent_table || !clk->parent_num)
|
||||
return 0;
|
||||
|
||||
if (!clk->src_width) {
|
||||
pr_err("sh_clk_init_parent: cannot select parent clock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = (ioread32(clk->mapped_reg) >> clk->src_shift);
|
||||
val &= (1 << clk->src_width) - 1;
|
||||
|
||||
if (val >= clk->parent_num) {
|
||||
pr_err("sh_clk_init_parent: parent table size failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk->parent = clk->parent_table[val];
|
||||
if (!clk->parent) {
|
||||
pr_err("sh_clk_init_parent: unable to set parent");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
|
||||
struct clk_ops *ops)
|
||||
{
|
||||
@@ -190,6 +222,9 @@ static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
|
||||
clkp->ops = ops;
|
||||
clkp->freq_table = freq_table + (k * freq_table_size);
|
||||
clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
|
||||
ret = sh_clk_init_parent(clkp);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
ret = clk_register(clkp);
|
||||
}
|
||||
@@ -217,7 +252,7 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
|
||||
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
|
||||
table, &clk->arch_flags);
|
||||
|
||||
idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
|
||||
idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
|
||||
|
||||
return clk->freq_table[idx].frequency;
|
||||
}
|
||||
@@ -235,15 +270,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
|
||||
*/
|
||||
|
||||
if (parent->flags & CLK_ENABLE_ON_INIT)
|
||||
value = __raw_readl(clk->enable_reg) & ~(1 << 7);
|
||||
value = ioread32(clk->mapped_reg) & ~(1 << 7);
|
||||
else
|
||||
value = __raw_readl(clk->enable_reg) | (1 << 7);
|
||||
value = ioread32(clk->mapped_reg) | (1 << 7);
|
||||
|
||||
ret = clk_reparent(clk, parent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
__raw_writel(value, clk->enable_reg);
|
||||
iowrite32(value, clk->mapped_reg);
|
||||
|
||||
/* Rebiuld the frequency table */
|
||||
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
|
||||
@@ -260,10 +295,10 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
|
||||
if (idx < 0)
|
||||
return idx;
|
||||
|
||||
value = __raw_readl(clk->enable_reg);
|
||||
value = ioread32(clk->mapped_reg);
|
||||
value &= ~(0xf << clk->enable_bit);
|
||||
value |= (idx << clk->enable_bit);
|
||||
__raw_writel(value, clk->enable_reg);
|
||||
iowrite32(value, clk->mapped_reg);
|
||||
|
||||
if (d4t->kick)
|
||||
d4t->kick(clk);
|
||||
@@ -273,13 +308,13 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
|
||||
|
||||
static int sh_clk_div4_enable(struct clk *clk)
|
||||
{
|
||||
__raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
|
||||
iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_clk_div4_disable(struct clk *clk)
|
||||
{
|
||||
__raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
|
||||
iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
|
||||
}
|
||||
|
||||
static struct clk_ops sh_clk_div4_clk_ops = {
|
||||
|
137
drivers/sh/pfc.c
137
drivers/sh/pfc.c
@@ -19,6 +19,75 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioport.h>
|
||||
|
||||
static void pfc_iounmap(struct pinmux_info *pip)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k = 0; k < pip->num_resources; k++)
|
||||
if (pip->window[k].virt)
|
||||
iounmap(pip->window[k].virt);
|
||||
|
||||
kfree(pip->window);
|
||||
pip->window = NULL;
|
||||
}
|
||||
|
||||
static int pfc_ioremap(struct pinmux_info *pip)
|
||||
{
|
||||
struct resource *res;
|
||||
int k;
|
||||
|
||||
if (!pip->num_resources)
|
||||
return 0;
|
||||
|
||||
pip->window = kzalloc(pip->num_resources * sizeof(*pip->window),
|
||||
GFP_NOWAIT);
|
||||
if (!pip->window)
|
||||
goto err1;
|
||||
|
||||
for (k = 0; k < pip->num_resources; k++) {
|
||||
res = pip->resource + k;
|
||||
WARN_ON(resource_type(res) != IORESOURCE_MEM);
|
||||
pip->window[k].phys = res->start;
|
||||
pip->window[k].size = resource_size(res);
|
||||
pip->window[k].virt = ioremap_nocache(res->start,
|
||||
resource_size(res));
|
||||
if (!pip->window[k].virt)
|
||||
goto err2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
pfc_iounmap(pip);
|
||||
err1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void __iomem *pfc_phys_to_virt(struct pinmux_info *pip,
|
||||
unsigned long address)
|
||||
{
|
||||
struct pfc_window *window;
|
||||
int k;
|
||||
|
||||
/* scan through physical windows and convert address */
|
||||
for (k = 0; k < pip->num_resources; k++) {
|
||||
window = pip->window + k;
|
||||
|
||||
if (address < window->phys)
|
||||
continue;
|
||||
|
||||
if (address >= (window->phys + window->size))
|
||||
continue;
|
||||
|
||||
return window->virt + (address - window->phys);
|
||||
}
|
||||
|
||||
/* no windows defined, register must be 1:1 mapped virt:phys */
|
||||
return (void __iomem *)address;
|
||||
}
|
||||
|
||||
static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
|
||||
{
|
||||
@@ -31,35 +100,35 @@ static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned long gpio_read_raw_reg(unsigned long reg,
|
||||
static unsigned long gpio_read_raw_reg(void __iomem *mapped_reg,
|
||||
unsigned long reg_width)
|
||||
{
|
||||
switch (reg_width) {
|
||||
case 8:
|
||||
return __raw_readb(reg);
|
||||
return ioread8(mapped_reg);
|
||||
case 16:
|
||||
return __raw_readw(reg);
|
||||
return ioread16(mapped_reg);
|
||||
case 32:
|
||||
return __raw_readl(reg);
|
||||
return ioread32(mapped_reg);
|
||||
}
|
||||
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_write_raw_reg(unsigned long reg,
|
||||
static void gpio_write_raw_reg(void __iomem *mapped_reg,
|
||||
unsigned long reg_width,
|
||||
unsigned long data)
|
||||
{
|
||||
switch (reg_width) {
|
||||
case 8:
|
||||
__raw_writeb(data, reg);
|
||||
iowrite8(data, mapped_reg);
|
||||
return;
|
||||
case 16:
|
||||
__raw_writew(data, reg);
|
||||
iowrite16(data, mapped_reg);
|
||||
return;
|
||||
case 32:
|
||||
__raw_writel(data, reg);
|
||||
iowrite32(data, mapped_reg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,11 +151,12 @@ static void gpio_write_bit(struct pinmux_data_reg *dr,
|
||||
else
|
||||
clear_bit(pos, &dr->reg_shadow);
|
||||
|
||||
gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow);
|
||||
gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
|
||||
}
|
||||
|
||||
static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
|
||||
unsigned long field_width, unsigned long in_pos)
|
||||
static int gpio_read_reg(void __iomem *mapped_reg, unsigned long reg_width,
|
||||
unsigned long field_width, unsigned long in_pos,
|
||||
unsigned long reg)
|
||||
{
|
||||
unsigned long data, mask, pos;
|
||||
|
||||
@@ -98,13 +168,13 @@ static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
|
||||
"r_width = %ld, f_width = %ld\n",
|
||||
reg, pos, reg_width, field_width);
|
||||
|
||||
data = gpio_read_raw_reg(reg, reg_width);
|
||||
data = gpio_read_raw_reg(mapped_reg, reg_width);
|
||||
return (data >> pos) & mask;
|
||||
}
|
||||
|
||||
static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
|
||||
static void gpio_write_reg(void __iomem *mapped_reg, unsigned long reg_width,
|
||||
unsigned long field_width, unsigned long in_pos,
|
||||
unsigned long value)
|
||||
unsigned long value, unsigned long reg)
|
||||
{
|
||||
unsigned long mask, pos;
|
||||
|
||||
@@ -120,13 +190,13 @@ static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
|
||||
|
||||
switch (reg_width) {
|
||||
case 8:
|
||||
__raw_writeb((__raw_readb(reg) & mask) | value, reg);
|
||||
iowrite8((ioread8(mapped_reg) & mask) | value, mapped_reg);
|
||||
break;
|
||||
case 16:
|
||||
__raw_writew((__raw_readw(reg) & mask) | value, reg);
|
||||
iowrite16((ioread16(mapped_reg) & mask) | value, mapped_reg);
|
||||
break;
|
||||
case 32:
|
||||
__raw_writel((__raw_readl(reg) & mask) | value, reg);
|
||||
iowrite32((ioread32(mapped_reg) & mask) | value, mapped_reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -147,6 +217,8 @@ static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
|
||||
if (!data_reg->reg_width)
|
||||
break;
|
||||
|
||||
data_reg->mapped_reg = pfc_phys_to_virt(gpioc, data_reg->reg);
|
||||
|
||||
for (n = 0; n < data_reg->reg_width; n++) {
|
||||
if (data_reg->enum_ids[n] == gpiop->enum_id) {
|
||||
gpiop->flags &= ~PINMUX_FLAG_DREG;
|
||||
@@ -179,7 +251,8 @@ static void setup_data_regs(struct pinmux_info *gpioc)
|
||||
if (!drp->reg_width)
|
||||
break;
|
||||
|
||||
drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width);
|
||||
drp->reg_shadow = gpio_read_raw_reg(drp->mapped_reg,
|
||||
drp->reg_width);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
@@ -266,12 +339,16 @@ static void write_config_reg(struct pinmux_info *gpioc,
|
||||
int index)
|
||||
{
|
||||
unsigned long ncomb, pos, value;
|
||||
void __iomem *mapped_reg;
|
||||
|
||||
ncomb = 1 << crp->field_width;
|
||||
pos = index / ncomb;
|
||||
value = index % ncomb;
|
||||
|
||||
gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value);
|
||||
mapped_reg = pfc_phys_to_virt(gpioc, crp->reg);
|
||||
|
||||
gpio_write_reg(mapped_reg, crp->reg_width, crp->field_width,
|
||||
pos, value, crp->reg);
|
||||
}
|
||||
|
||||
static int check_config_reg(struct pinmux_info *gpioc,
|
||||
@@ -279,13 +356,16 @@ static int check_config_reg(struct pinmux_info *gpioc,
|
||||
int index)
|
||||
{
|
||||
unsigned long ncomb, pos, value;
|
||||
void __iomem *mapped_reg;
|
||||
|
||||
ncomb = 1 << crp->field_width;
|
||||
pos = index / ncomb;
|
||||
value = index % ncomb;
|
||||
|
||||
if (gpio_read_reg(crp->reg, crp->reg_width,
|
||||
crp->field_width, pos) == value)
|
||||
mapped_reg = pfc_phys_to_virt(gpioc, crp->reg);
|
||||
|
||||
if (gpio_read_reg(mapped_reg, crp->reg_width,
|
||||
crp->field_width, pos, crp->reg) == value)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
@@ -564,7 +644,7 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
|
||||
if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
|
||||
return gpio_read_reg(dr->mapped_reg, dr->reg_width, 1, bit, dr->reg);
|
||||
}
|
||||
|
||||
static int sh_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
@@ -606,10 +686,15 @@ static int sh_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
int register_pinmux(struct pinmux_info *pip)
|
||||
{
|
||||
struct gpio_chip *chip = &pip->chip;
|
||||
int ret;
|
||||
|
||||
pr_info("%s handling gpio %d -> %d\n",
|
||||
pip->name, pip->first_gpio, pip->last_gpio);
|
||||
|
||||
ret = pfc_ioremap(pip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
setup_data_regs(pip);
|
||||
|
||||
chip->request = sh_gpio_request;
|
||||
@@ -627,12 +712,16 @@ int register_pinmux(struct pinmux_info *pip)
|
||||
chip->base = pip->first_gpio;
|
||||
chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1;
|
||||
|
||||
return gpiochip_add(chip);
|
||||
ret = gpiochip_add(chip);
|
||||
if (ret < 0)
|
||||
pfc_iounmap(pip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unregister_pinmux(struct pinmux_info *pip)
|
||||
{
|
||||
pr_info("%s deregistering\n", pip->name);
|
||||
|
||||
pfc_iounmap(pip);
|
||||
return gpiochip_remove(&pip->chip);
|
||||
}
|
||||
|
Reference in New Issue
Block a user