* [PATCH 12/16] pinctrl: samsung: Use per-bank IRQ domain for wake-up interrupts
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
This patch reworks wake-up interrupt handling in pinctrl-exynos driver,
so each pin bank, which provides wake-up interrupts, has its own IRQ
domain.
Information about whether given pin bank provides wake-up interrupts,
how many and whether they are separate or muxed are parsed from device
tree.
It gives following advantages:
- interrupts can be specified in device tree in a more readable way,
e.g. :
device {
/* ... */
interrupt-parent = <&gpx2>;
interrupts = <4 0>;
/* ... */
};
- the amount and layout of interrupts is not hardcoded in the driver
anymore
- bank and pin of each wake-up interrupt can be easily identified, to
allow operations, such as setting the pin to EINT function, from
irq_set_type() callback
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-exynos.c | 159 +++++++++++++++++++++++---------------
drivers/pinctrl/pinctrl-exynos.h | 17 +++-
drivers/pinctrl/pinctrl-samsung.c | 9 ++-
drivers/pinctrl/pinctrl-samsung.h | 6 +-
4 files changed, 119 insertions(+), 72 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 53ed5d9..fa6a5be 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -218,46 +218,43 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
static void exynos_wkup_irq_unmask(struct irq_data *irqd)
{
- struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
- unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
- unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
- unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2);
+ struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = b->drvdata;
+ unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
unsigned long mask;
mask = readl(d->virt_base + reg_mask);
- mask &= ~(1 << pin);
+ mask &= ~(1 << irqd->hwirq);
writel(mask, d->virt_base + reg_mask);
}
static void exynos_wkup_irq_mask(struct irq_data *irqd)
{
- struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
- unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
- unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
- unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2);
+ struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = b->drvdata;
+ unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
unsigned long mask;
mask = readl(d->virt_base + reg_mask);
- mask |= 1 << pin;
+ mask |= 1 << irqd->hwirq;
writel(mask, d->virt_base + reg_mask);
}
static void exynos_wkup_irq_ack(struct irq_data *irqd)
{
- struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
- unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
- unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
- unsigned long pend = d->ctrl->weint_pend + (bank << 2);
+ struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = b->drvdata;
+ unsigned long pend = d->ctrl->weint_pend + b->eint_offset;
- writel(1 << pin, d->virt_base + pend);
+ writel(1 << irqd->hwirq, d->virt_base + pend);
}
static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
{
- struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
- unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
- unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
- unsigned long reg_con = d->ctrl->weint_con + (bank << 2);
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ unsigned int pin = irqd->hwirq;
+ unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset;
unsigned long shift = EXYNOS_EINT_CON_LEN * pin;
unsigned long con, trig_type;
@@ -309,6 +306,7 @@ static struct irq_chip exynos_wkup_irq_chip = {
static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
{
struct exynos_weint_data *eintd = irq_get_handler_data(irq);
+ struct samsung_pin_bank *bank = eintd->bank;
struct irq_chip *chip = irq_get_chip(irq);
int eint_irq;
@@ -318,20 +316,20 @@ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
if (chip->irq_ack)
chip->irq_ack(&desc->irq_data);
- eint_irq = irq_linear_revmap(eintd->domain, eintd->irq);
+ eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq);
generic_handle_irq(eint_irq);
chip->irq_unmask(&desc->irq_data);
chained_irq_exit(chip, desc);
}
-static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend,
- struct irq_domain *domain)
+static inline void exynos_irq_demux_eint(unsigned long pend,
+ struct irq_domain *domain)
{
unsigned int irq;
while (pend) {
irq = fls(pend) - 1;
- generic_handle_irq(irq_find_mapping(domain, irq_base + irq));
+ generic_handle_irq(irq_find_mapping(domain, irq));
pend &= ~(1 << irq);
}
}
@@ -340,18 +338,22 @@ static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend,
static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_get_chip(irq);
- struct exynos_weint_data *eintd = irq_get_handler_data(irq);
- struct samsung_pinctrl_drv_data *d = eintd->domain->host_data;
+ struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq);
+ struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata;
+ struct samsung_pin_ctrl *ctrl = d->ctrl;
unsigned long pend;
unsigned long mask;
+ int i;
chained_irq_enter(chip, desc);
- pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8);
- mask = readl(d->virt_base + d->ctrl->weint_mask + 0x8);
- exynos_irq_demux_eint(16, pend & ~mask, eintd->domain);
- pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC);
- mask = readl(d->virt_base + d->ctrl->weint_mask + 0xC);
- exynos_irq_demux_eint(24, pend & ~mask, eintd->domain);
+
+ for (i = 0; i < eintd->nr_banks; ++i) {
+ struct samsung_pin_bank *b = eintd->banks[i];
+ pend = readl(d->virt_base + ctrl->weint_pend + b->eint_offset);
+ mask = readl(d->virt_base + ctrl->weint_mask + b->eint_offset);
+ exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
+ }
+
chained_irq_exit(chip, desc);
}
@@ -381,7 +383,11 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
struct device *dev = d->dev;
struct device_node *wkup_np = NULL;
struct device_node *np;
+ struct samsung_pin_bank *bank;
struct exynos_weint_data *weint_data;
+ struct exynos_muxed_weint_data *muxed_data;
+ unsigned int muxed_banks = 0;
+ unsigned int i;
int idx, irq;
u32 val;
int ret;
@@ -395,11 +401,6 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
if (!wkup_np)
return -ENODEV;
- ret = of_property_read_u32(wkup_np, "samsung,weint-count", &val);
- if (ret)
- return -EINVAL;
- d->ctrl->nr_wint = val;
-
ret = of_property_read_u32(wkup_np, "samsung,weint-con", &val);
if (ret)
return -EINVAL;
@@ -415,40 +416,74 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
return -EINVAL;
d->ctrl->weint_pend = val;
- d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint,
- &exynos_wkup_irqd_ops, d);
- if (!d->wkup_irqd) {
- dev_err(dev, "wakeup irq domain allocation failed\n");
- return -ENXIO;
- }
+ bank = d->ctrl->pin_banks;
+ for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ if (bank->eint_type != EINT_TYPE_WKUP)
+ continue;
- weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL);
- if (!weint_data) {
- dev_err(dev, "could not allocate memory for weint_data\n");
- return -ENOMEM;
- }
+ bank->irq_domain = irq_domain_add_linear(bank->of_node,
+ bank->nr_pins, &exynos_wkup_irqd_ops, bank);
+ if (!bank->irq_domain) {
+ dev_err(dev, "wkup irq domain add failed\n");
+ return -ENXIO;
+ }
- irq = irq_of_parse_and_map(wkup_np, 16);
- if (irq) {
- weint_data[16].domain = d->wkup_irqd;
- irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
- irq_set_handler_data(irq, &weint_data[16]);
- } else {
- dev_err(dev, "irq number for EINT16-32 not found\n");
- }
+ if (!of_find_property(bank->of_node, "interrupts", NULL)) {
+ bank->eint_type = EINT_TYPE_WKUP_MUX;
+ ++muxed_banks;
+ continue;
+ }
- for (idx = 0; idx < 16; idx++) {
- weint_data[idx].domain = d->wkup_irqd;
- weint_data[idx].irq = idx;
+ weint_data = devm_kzalloc(dev, bank->nr_pins
+ * sizeof(*weint_data), GFP_KERNEL);
+ if (!weint_data) {
+ dev_err(dev, "could not allocate memory for weint_data\n");
+ return -ENOMEM;
+ }
- irq = irq_of_parse_and_map(wkup_np, idx);
- if (irq) {
+ for (idx = 0; idx < bank->nr_pins; ++idx) {
+ irq = irq_of_parse_and_map(bank->of_node, idx);
+ if (!irq) {
+ dev_err(dev, "irq number for eint-%s-%d not found\n",
+ bank->name, idx);
+ continue;
+ }
+ weint_data[idx].irq = idx;
+ weint_data[idx].bank = bank;
irq_set_handler_data(irq, &weint_data[idx]);
irq_set_chained_handler(irq, exynos_irq_eint0_15);
- } else {
- dev_err(dev, "irq number for eint-%x not found\n", idx);
}
}
+
+ if (!muxed_banks)
+ return 0;
+
+ irq = irq_of_parse_and_map(wkup_np, 0);
+ if (!irq) {
+ dev_err(dev, "irq number for muxed EINTs not found\n");
+ return 0;
+ }
+
+ muxed_data = devm_kzalloc(dev, sizeof(*muxed_data)
+ + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL);
+ if (!muxed_data) {
+ dev_err(dev, "could not allocate memory for muxed_data\n");
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
+ irq_set_handler_data(irq, muxed_data);
+
+ bank = d->ctrl->pin_banks;
+ idx = 0;
+ for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ if (bank->eint_type != EINT_TYPE_WKUP_MUX)
+ continue;
+
+ muxed_data->banks[idx++] = bank;
+ }
+ muxed_data->nr_banks = muxed_banks;
+
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
index 30aca2b..a94d6fc 100644
--- a/drivers/pinctrl/pinctrl-exynos.h
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -40,10 +40,21 @@
/**
* struct exynos_weint_data: irq specific data for all the wakeup interrupts
* generated by the external wakeup interrupt controller.
- * @domain: irq domain representing the external wakeup interrupts
* @irq: interrupt number within the domain.
+ * @bank: bank responsible for this interrupt
*/
struct exynos_weint_data {
- struct irq_domain *domain;
- u32 irq;
+ unsigned int irq;
+ struct samsung_pin_bank *bank;
+};
+
+/**
+ * struct exynos_muxed_weint_data: irq specific data for muxed wakeup interrupts
+ * generated by the external wakeup interrupt controller.
+ * @nr_banks: count of banks being part of the mux
+ * @banks: array of banks being part of the mux
+ */
+struct exynos_muxed_weint_data {
+ unsigned int nr_banks;
+ struct samsung_pin_bank *banks[];
};
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 4ffd14c..215a7e5 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -615,10 +615,10 @@ static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev,
*/
for_each_child_of_node(dev_np, cfg_np) {
u32 function;
- if (of_find_property(cfg_np, "interrupt-controller", NULL))
- continue;
if (of_find_property(cfg_np, "gpio-controller", NULL))
continue;
+ if (of_find_property(cfg_np, "compatible", NULL))
+ continue;
ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np,
&drvdata->pctl, &pin_list, &npins);
@@ -894,7 +894,10 @@ static int samsung_pinctrl_parse_dt_bank(struct samsung_pin_bank *bank,
return 0;
}
- bank->eint_type = EINT_TYPE_GPIO;
+ if (of_find_property(np, "samsung,wkup-eint", NULL))
+ bank->eint_type = EINT_TYPE_WKUP;
+ else
+ bank->eint_type = EINT_TYPE_GPIO;
ret = of_property_read_u32(np, "samsung,eint-offset", &val);
if (ret)
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index f27b1e0..355f4e2 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -66,6 +66,7 @@ enum pincfg_type {
* @EINT_TYPE_NONE: bank does not support external interrupts
* @EINT_TYPE_GPIO: bank supportes external gpio interrupts
* @EINT_TYPE_WKUP: bank supportes external wakeup interrupts
+ * @EINT_TYPE_WKUP_MUX: bank supports multiplexed external wakeup interrupts
*
* Samsung GPIO controller groups all the available pins into banks. The pins
* in a pin bank can support external gpio interrupts or external wakeup
@@ -78,6 +79,7 @@ enum eint_type {
EINT_TYPE_NONE,
EINT_TYPE_GPIO,
EINT_TYPE_WKUP,
+ EINT_TYPE_WKUP_MUX,
};
/* maximum length of a pin in pin descriptor (example: "gpa0-0") */
@@ -157,7 +159,6 @@ struct samsung_pin_ctrl_variant {
* @nr_banks: number of pin banks.
* @base: starting system wide pin number.
* @nr_pins: number of pins supported by the controller.
- * @nr_wint: number of external wakeup interrupts supported.
* @geint_con: offset of the ext-gpio controller registers.
* @geint_mask: offset of the ext-gpio interrupt mask registers.
* @geint_pend: offset of the ext-gpio interrupt pending registers.
@@ -177,7 +178,6 @@ struct samsung_pin_ctrl {
u32 base;
u32 nr_pins;
- u32 nr_wint;
u32 geint_con;
u32 geint_mask;
@@ -220,8 +220,6 @@ struct samsung_pinctrl_drv_data {
unsigned int nr_groups;
const struct samsung_pmx_func *pmx_functions;
unsigned int nr_functions;
-
- struct irq_domain *wkup_irqd;
};
/**
--
1.7.12
^ permalink raw reply related
* [PATCH 11/16] pinctrl: samsung: Use one GPIO chip per pin bank
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
This patch modifies the pinctrl-samsung driver to register one GPIO chip
per pin bank, instead of a single chip for all pin banks of the
controller.
It simplifies GPIO accesses a lot (constant time instead of looping
through the list of banks to find the right one) and should have a good
effect on performance of any bit-banging driver.
In addition it allows to reference GPIO pins by a phandle to the bank
node and a local pin offset inside of the bank (similar to previous
gpiolib driver), which is more clear and readable than using indices
relative to the whole pin controller.
Example:
device {
/* ... */
gpios = <&gpk0 4 0>;
/* ... */
};
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-samsung.c | 119 ++++++++++++++++++++++++--------------
drivers/pinctrl/pinctrl-samsung.h | 12 ++--
2 files changed, 81 insertions(+), 50 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index e63a365..4ffd14c 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -48,6 +48,11 @@ struct pin_config {
static unsigned int pin_base = 0;
+static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
+{
+ return container_of(gc, struct samsung_pin_bank, gpio_chip);
+}
+
/* check if the selector is a valid pin group selector */
static int samsung_get_group_count(struct pinctrl_dev *pctldev)
{
@@ -333,9 +338,12 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
void __iomem *reg;
u32 data, pin_offset, mask, shift;
+ bank = gc_to_pin_bank(range->gc);
drvdata = pinctrl_dev_get_drvdata(pctldev);
- pin_to_reg_bank(drvdata, offset, ®, &pin_offset, &bank);
+ pin_offset = offset - bank->pin_base;
+ reg = drvdata->virt_base + bank->pctl_offset;
+
mask = (1 << bank->func_width) - 1;
shift = pin_offset * bank->func_width;
@@ -469,17 +477,16 @@ static struct pinconf_ops samsung_pinconf_ops = {
/* gpiolib gpio_set callback function */
static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
+ struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
void __iomem *reg;
- u32 pin_offset, data;
- struct samsung_pinctrl_drv_data *drvdata;
+ u32 data;
- drvdata = dev_get_drvdata(gc->dev);
+ reg = bank->drvdata->virt_base + bank->pctl_offset;
- pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL);
data = readl(reg + DAT_REG);
- data &= ~(1 << pin_offset);
+ data &= ~(1 << offset);
if (value)
- data |= 1 << pin_offset;
+ data |= 1 << offset;
writel(data, reg + DAT_REG);
}
@@ -487,14 +494,13 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
{
void __iomem *reg;
- u32 pin_offset, data;
- struct samsung_pinctrl_drv_data *drvdata;
+ u32 data;
+ struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
- drvdata = dev_get_drvdata(gc->dev);
+ reg = bank->drvdata->virt_base + bank->pctl_offset;
- pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL);
data = readl(reg + DAT_REG);
- data >>= pin_offset;
+ data >>= offset;
data &= 1;
return data;
}
@@ -726,12 +732,16 @@ static int __init samsung_pinctrl_register(struct platform_device *pdev,
return -EINVAL;
}
- drvdata->grange.name = "samsung-pctrl-gpio-range";
- drvdata->grange.id = 0;
- drvdata->grange.base = drvdata->ctrl->base;
- drvdata->grange.npins = drvdata->ctrl->nr_pins;
- drvdata->grange.gc = drvdata->gc;
- pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange);
+ for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) {
+ pin_bank = &drvdata->ctrl->pin_banks[bank];
+ pin_bank->grange.name = pin_bank->name;
+ pin_bank->grange.id = bank;
+ pin_bank->grange.pin_base = pin_bank->pin_base;
+ pin_bank->grange.base = pin_bank->gpio_chip.base;
+ pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
+ pin_bank->grange.gc = &pin_bank->gpio_chip;
+ pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
+ }
ret = samsung_pinctrl_parse_dt(pdev, drvdata);
if (ret) {
@@ -742,49 +752,68 @@ static int __init samsung_pinctrl_register(struct platform_device *pdev,
return 0;
}
+static const struct gpio_chip samsung_gpiolib_chip = {
+ .set = samsung_gpio_set,
+ .get = samsung_gpio_get,
+ .direction_input = samsung_gpio_direction_input,
+ .direction_output = samsung_gpio_direction_output,
+ .owner = THIS_MODULE,
+};
+
/* register the gpiolib interface with the gpiolib subsystem */
static int __init samsung_gpiolib_register(struct platform_device *pdev,
struct samsung_pinctrl_drv_data *drvdata)
{
+ struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+ struct samsung_pin_bank *bank = ctrl->pin_banks;
struct gpio_chip *gc;
int ret;
-
- gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
- if (!gc) {
- dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n");
- return -ENOMEM;
- }
-
- drvdata->gc = gc;
- gc->base = drvdata->ctrl->base;
- gc->ngpio = drvdata->ctrl->nr_pins;
- gc->dev = &pdev->dev;
- gc->set = samsung_gpio_set;
- gc->get = samsung_gpio_get;
- gc->direction_input = samsung_gpio_direction_input;
- gc->direction_output = samsung_gpio_direction_output;
- gc->label = drvdata->ctrl->label;
- gc->owner = THIS_MODULE;
- ret = gpiochip_add(gc);
- if (ret) {
- dev_err(&pdev->dev, "failed to register gpio_chip %s, error "
- "code: %d\n", gc->label, ret);
- return ret;
+ int i;
+
+ for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+ bank->gpio_chip = samsung_gpiolib_chip;
+
+ gc = &bank->gpio_chip;
+ gc->base = ctrl->base + bank->pin_base;
+ gc->ngpio = bank->nr_pins;
+ gc->dev = &pdev->dev;
+ gc->of_node = bank->of_node;
+ gc->label = bank->name;
+
+ ret = gpiochip_add(gc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
+ gc->label, ret);
+ goto fail;
+ }
}
return 0;
+
+fail:
+ for (--i, --bank; i >= 0; --i, --bank)
+ if (gpiochip_remove(&bank->gpio_chip))
+ dev_err(&pdev->dev, "gpio chip %s remove failed\n",
+ bank->gpio_chip.label);
+ return ret;
}
/* unregister the gpiolib interface with the gpiolib subsystem */
static int __init samsung_gpiolib_unregister(struct platform_device *pdev,
struct samsung_pinctrl_drv_data *drvdata)
{
- int ret = gpiochip_remove(drvdata->gc);
- if (ret) {
+ struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+ struct samsung_pin_bank *bank = ctrl->pin_banks;
+ int ret = 0;
+ int i;
+
+ for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank)
+ ret = gpiochip_remove(&bank->gpio_chip);
+
+ if (ret)
dev_err(&pdev->dev, "gpio chip remove failed\n");
- return ret;
- }
- return 0;
+
+ return ret;
}
static const struct of_device_id samsung_pinctrl_dt_match[];
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 470e11b..f27b1e0 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -23,6 +23,8 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
+#include <linux/gpio.h>
+
/* register offsets within a pin bank */
#define DAT_REG 0x4
#define PUD_REG 0x8
@@ -113,6 +115,8 @@ struct samsung_pinctrl_drv_data;
* @of_node: node of pin bank in device tree
* @drvdata: link to controller driver data
* @irq_domain: IRQ domain of the bank.
+ * @gpio_chip: GPIO chip of the bank.
+ * @grange: linux gpio pin range supported by this bank.
*/
struct samsung_pin_bank {
u32 pctl_offset;
@@ -130,6 +134,9 @@ struct samsung_pin_bank {
struct device_node *of_node;
struct samsung_pinctrl_drv_data *drvdata;
struct irq_domain *irq_domain;
+
+ struct gpio_chip gpio_chip;
+ struct pinctrl_gpio_range grange;
};
/**
@@ -199,8 +206,6 @@ struct samsung_pin_ctrl {
* @nr_groups: number of such pin groups.
* @pmx_functions: list of pin functions available to the driver.
* @nr_function: number of such pin functions.
- * @gc: gpio_chip instance registered with gpiolib.
- * @grange: linux gpio pin range supported by this controller.
*/
struct samsung_pinctrl_drv_data {
void __iomem *virt_base;
@@ -217,9 +222,6 @@ struct samsung_pinctrl_drv_data {
unsigned int nr_functions;
struct irq_domain *wkup_irqd;
-
- struct gpio_chip *gc;
- struct pinctrl_gpio_range grange;
};
/**
--
1.7.12
^ permalink raw reply related
* [PATCH 10/16] pinctrl: samsung: Do not pass gpio_chip to pin_to_reg_bank
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
The pointer to gpio_chip passed to pin_to_reg_bank utility function is
used only to retrieve a pointer to samsung_pinctrl_drv_data structure.
This patch modifies the function and its users to pass a pointer to
samsung_pinctrl_drv_data directly.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-samsung.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 6ae82d5..e63a365 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -252,14 +252,12 @@ static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev,
* given a pin number that is local to a pin controller, find out the pin bank
* and the register base of the pin bank.
*/
-static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin,
- void __iomem **reg, u32 *offset,
+static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
+ unsigned pin, void __iomem **reg, u32 *offset,
struct samsung_pin_bank **bank)
{
- struct samsung_pinctrl_drv_data *drvdata;
struct samsung_pin_bank *b;
- drvdata = dev_get_drvdata(gc->dev);
b = drvdata->ctrl->pin_banks;
while ((pin >= b->pin_base) &&
@@ -294,7 +292,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
* pin function number in the config register.
*/
for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) {
- pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base,
+ pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base,
®, &pin_offset, &bank);
mask = (1 << bank->func_width) - 1;
shift = pin_offset * bank->func_width;
@@ -331,10 +329,13 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range, unsigned offset, bool input)
{
struct samsung_pin_bank *bank;
+ struct samsung_pinctrl_drv_data *drvdata;
void __iomem *reg;
u32 data, pin_offset, mask, shift;
- pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank);
+ drvdata = pinctrl_dev_get_drvdata(pctldev);
+
+ pin_to_reg_bank(drvdata, offset, ®, &pin_offset, &bank);
mask = (1 << bank->func_width) - 1;
shift = pin_offset * bank->func_width;
@@ -368,7 +369,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
u32 cfg_value, cfg_reg;
drvdata = pinctrl_dev_get_drvdata(pctldev);
- pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base,
+ pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base,
&pin_offset, &bank);
switch (cfg_type) {
@@ -470,8 +471,11 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
void __iomem *reg;
u32 pin_offset, data;
+ struct samsung_pinctrl_drv_data *drvdata;
- pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL);
+ drvdata = dev_get_drvdata(gc->dev);
+
+ pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL);
data = readl(reg + DAT_REG);
data &= ~(1 << pin_offset);
if (value)
@@ -484,8 +488,11 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
{
void __iomem *reg;
u32 pin_offset, data;
+ struct samsung_pinctrl_drv_data *drvdata;
+
+ drvdata = dev_get_drvdata(gc->dev);
- pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL);
+ pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL);
data = readl(reg + DAT_REG);
data >>= pin_offset;
data &= 1;
--
1.7.12
^ permalink raw reply related
* [PATCH 09/16] pinctrl: exynos: Use one IRQ domain per pin bank
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
Instead of registering one IRQ domain for all pin banks of a pin
controller, this patch implements registration of per-bank domains.
At a cost of a little memory overhead (~2.5KiB for all GPIO interrupts
of Exynos4x12) it simplifies driver code and device tree sources,
because GPIO interrupts can be now specified per banks.
Example:
device {
/* ... */
interrupt-parent = <&gpa1>;
interrupts = <3 0>;
/* ... */
};
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-exynos.c | 117 +++++++++++---------------------------
drivers/pinctrl/pinctrl-exynos.h | 12 ----
drivers/pinctrl/pinctrl-samsung.c | 5 +-
drivers/pinctrl/pinctrl-samsung.h | 7 +--
4 files changed, 36 insertions(+), 105 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 340bfc2..53ed5d9 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -40,46 +40,46 @@ static const struct of_device_id exynos_wkup_irq_ids[] = {
static void exynos_gpio_irq_unmask(struct irq_data *irqd)
{
- struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
- struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
- unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset;
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
unsigned long mask;
mask = readl(d->virt_base + reg_mask);
- mask &= ~(1 << edata->pin);
+ mask &= ~(1 << irqd->hwirq);
writel(mask, d->virt_base + reg_mask);
}
static void exynos_gpio_irq_mask(struct irq_data *irqd)
{
- struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
- struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
- unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset;
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
unsigned long mask;
mask = readl(d->virt_base + reg_mask);
- mask |= 1 << edata->pin;
+ mask |= 1 << irqd->hwirq;
writel(mask, d->virt_base + reg_mask);
}
static void exynos_gpio_irq_ack(struct irq_data *irqd)
{
- struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
- struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
- unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset;
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset;
- writel(1 << edata->pin, d->virt_base + reg_pend);
+ writel(1 << irqd->hwirq, d->virt_base + reg_pend);
}
static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
{
- struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
struct samsung_pin_ctrl *ctrl = d->ctrl;
- struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
- struct samsung_pin_bank *bank = edata->bank;
- unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin;
+ unsigned int pin = irqd->hwirq;
+ unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
unsigned int con, trig_type;
- unsigned long reg_con = ctrl->geint_con + edata->eint_offset;
+ unsigned long reg_con = ctrl->geint_con + bank->eint_offset;
unsigned int mask;
switch (type) {
@@ -114,7 +114,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
writel(con, d->virt_base + reg_con);
reg_con = bank->pctl_offset;
- shift = edata->pin * bank->func_width;
+ shift = pin * bank->func_width;
mask = (1 << bank->func_width) - 1;
con = readl(d->virt_base + reg_con);
@@ -136,81 +136,23 @@ static struct irq_chip exynos_gpio_irq_chip = {
.irq_set_type = exynos_gpio_irq_set_type,
};
-/*
- * given a controller-local external gpio interrupt number, prepare the handler
- * data for it.
- */
-static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw,
- struct samsung_pinctrl_drv_data *d)
-{
- struct samsung_pin_bank *bank = d->ctrl->pin_banks;
- struct exynos_geint_data *eint_data;
- unsigned int nr_banks = d->ctrl->nr_banks, idx;
- unsigned int irq_base = 0;
-
- if (hw >= d->ctrl->nr_gint) {
- dev_err(d->dev, "unsupported ext-gpio interrupt\n");
- return NULL;
- }
-
- for (idx = 0; idx < nr_banks; idx++, bank++) {
- if (bank->eint_type != EINT_TYPE_GPIO)
- continue;
- if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins)))
- break;
- irq_base += bank->nr_pins;
- }
-
- if (idx == nr_banks) {
- dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n");
- return NULL;
- }
-
- eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL);
- if (!eint_data) {
- dev_err(d->dev, "no memory for eint-gpio data\n");
- return NULL;
- }
-
- eint_data->bank = bank;
- eint_data->pin = hw - irq_base;
- eint_data->eint_offset = bank->eint_offset;
- return eint_data;
-}
-
static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
- struct samsung_pinctrl_drv_data *d = h->host_data;
- struct exynos_geint_data *eint_data;
-
- eint_data = exynos_get_eint_data(hw, d);
- if (!eint_data)
- return -EINVAL;
+ struct samsung_pin_bank *b = h->host_data;
- irq_set_handler_data(virq, eint_data);
- irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_data(virq, b);
irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip,
handle_level_irq);
set_irq_flags(virq, IRQF_VALID);
return 0;
}
-static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq)
-{
- struct samsung_pinctrl_drv_data *d = h->host_data;
- struct exynos_geint_data *eint_data;
-
- eint_data = irq_get_handler_data(virq);
- devm_kfree(d->dev, eint_data);
-}
-
/*
* irq domain callbacks for external gpio interrupt controller.
*/
static const struct irq_domain_ops exynos_gpio_irqd_ops = {
.map = exynos_gpio_irq_map,
- .unmap = exynos_gpio_irq_unmap,
.xlate = irq_domain_xlate_twocell,
};
@@ -229,7 +171,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
return IRQ_HANDLED;
bank += (group - 1);
- virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin);
+ virq = irq_linear_revmap(bank->irq_domain, pin);
if (!virq)
return IRQ_NONE;
generic_handle_irq(virq);
@@ -242,8 +184,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
*/
static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
{
+ struct samsung_pin_bank *bank;
struct device *dev = d->dev;
unsigned int ret;
+ unsigned int i;
if (!d->irq) {
dev_err(dev, "irq number not available\n");
@@ -257,11 +201,16 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
return -ENXIO;
}
- d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint,
- &exynos_gpio_irqd_ops, d);
- if (!d->gpio_irqd) {
- dev_err(dev, "gpio irq domain allocation failed\n");
- return -ENXIO;
+ bank = d->ctrl->pin_banks;
+ for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ if (bank->eint_type != EINT_TYPE_GPIO)
+ continue;
+ bank->irq_domain = irq_domain_add_linear(bank->of_node,
+ bank->nr_pins, &exynos_gpio_irqd_ops, bank);
+ if (!bank->irq_domain) {
+ dev_err(dev, "gpio irq domain add failed\n");
+ return -ENXIO;
+ }
}
return 0;
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
index a72cfc7..30aca2b 100644
--- a/drivers/pinctrl/pinctrl-exynos.h
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -38,18 +38,6 @@
#define EXYNOS_EINT_MAX_PER_BANK 8
/**
- * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks.
- * @bank: pin bank from which this gpio interrupt originates.
- * @pin: pin number within the bank.
- * @eint_offset: offset to be added to the con/pend/mask register bank base.
- */
-struct exynos_geint_data {
- struct samsung_pin_bank *bank;
- u32 pin;
- u32 eint_offset;
-};
-
-/**
* struct exynos_weint_data: irq specific data for all the wakeup interrupts
* generated by the external wakeup interrupt controller.
* @domain: irq domain representing the external wakeup interrupts
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 63c76ec..6ae82d5 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -926,10 +926,8 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
b->drvdata = d;
b->pin_base = ctrl->nr_pins;
ctrl->nr_pins += b->nr_pins;
- if (b->eint_type == EINT_TYPE_GPIO) {
- b->irq_base = eint_cnt;
+ if (b->eint_type == EINT_TYPE_GPIO)
eint_cnt += b->nr_pins;
- }
++b;
}
@@ -959,7 +957,6 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
ctrl->pin_banks = banks;
ctrl->nr_banks = bank_cnt;
- ctrl->nr_gint = eint_cnt;
ctrl->label = node->name;
ctrl->eint_wkup_init = variant->eint_wkup_init;
ctrl->base = pin_base;
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 9e30081..470e11b 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -109,10 +109,10 @@ struct samsung_pinctrl_drv_data;
* @conpdn_width: width of the sleep mode function selector bin field.
* @pudpdn_width: width of the sleep mode pull up/down selector bit field.
* @eint_type: type of the external interrupt supported by the bank.
- * @irq_base: starting controller local irq number of the bank.
* @name: name to be prefixed for each pin in this pin bank.
* @of_node: node of pin bank in device tree
* @drvdata: link to controller driver data
+ * @irq_domain: IRQ domain of the bank.
*/
struct samsung_pin_bank {
u32 pctl_offset;
@@ -125,11 +125,11 @@ struct samsung_pin_bank {
u8 pudpdn_width;
enum eint_type eint_type;
u32 eint_offset;
- u32 irq_base;
const char *name;
struct device_node *of_node;
struct samsung_pinctrl_drv_data *drvdata;
+ struct irq_domain *irq_domain;
};
/**
@@ -150,7 +150,6 @@ struct samsung_pin_ctrl_variant {
* @nr_banks: number of pin banks.
* @base: starting system wide pin number.
* @nr_pins: number of pins supported by the controller.
- * @nr_gint: number of external gpio interrupts supported.
* @nr_wint: number of external wakeup interrupts supported.
* @geint_con: offset of the ext-gpio controller registers.
* @geint_mask: offset of the ext-gpio interrupt mask registers.
@@ -171,7 +170,6 @@ struct samsung_pin_ctrl {
u32 base;
u32 nr_pins;
- u32 nr_gint;
u32 nr_wint;
u32 geint_con;
@@ -218,7 +216,6 @@ struct samsung_pinctrl_drv_data {
const struct samsung_pmx_func *pmx_functions;
unsigned int nr_functions;
- struct irq_domain *gpio_irqd;
struct irq_domain *wkup_irqd;
struct gpio_chip *gc;
--
1.7.12
^ permalink raw reply related
* [PATCH 08/16] pinctrl: samsung: Hold pointer to driver data in bank struct
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
The pointer will be used by further extensions added to the driver.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-samsung.c | 20 +++++++++++---------
drivers/pinctrl/pinctrl-samsung.h | 2 ++
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index c988a4e..63c76ec 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -870,11 +870,12 @@ static int samsung_pinctrl_parse_dt_bank(struct samsung_pin_bank *bank,
/* retrieve the soc specific data */
static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
- struct platform_device *pdev)
+ struct platform_device *pdev,
+ struct samsung_pinctrl_drv_data *d)
{
int id;
const struct of_device_id *match;
- const struct device_node *node = pdev->dev.of_node;
+ struct device_node *node = pdev->dev.of_node;
struct device_node *bank_np;
struct samsung_pin_ctrl *ctrl;
struct samsung_pin_bank *banks, *b;
@@ -884,7 +885,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
u32 val;
int ret;
- id = of_alias_get_id(pdev->dev.of_node, "pinctrl");
+ id = of_alias_get_id(node, "pinctrl");
if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id\n");
return NULL;
@@ -922,6 +923,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
continue;
if (samsung_pinctrl_parse_dt_bank(b, bank_np))
return NULL;
+ b->drvdata = d;
b->pin_base = ctrl->nr_pins;
ctrl->nr_pins += b->nr_pins;
if (b->eint_type == EINT_TYPE_GPIO) {
@@ -979,18 +981,18 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev)
return -ENODEV;
}
- ctrl = samsung_pinctrl_get_soc_data(pdev);
- if (!ctrl) {
- dev_err(&pdev->dev, "driver data not available\n");
- return -EINVAL;
- }
-
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
dev_err(dev, "failed to allocate memory for driver's "
"private data\n");
return -ENOMEM;
}
+
+ ctrl = samsung_pinctrl_get_soc_data(pdev, drvdata);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "driver data not available\n");
+ return -EINVAL;
+ }
drvdata->ctrl = ctrl;
drvdata->dev = dev;
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index b7b74cc..9e30081 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -112,6 +112,7 @@ struct samsung_pinctrl_drv_data;
* @irq_base: starting controller local irq number of the bank.
* @name: name to be prefixed for each pin in this pin bank.
* @of_node: node of pin bank in device tree
+ * @drvdata: link to controller driver data
*/
struct samsung_pin_bank {
u32 pctl_offset;
@@ -128,6 +129,7 @@ struct samsung_pin_bank {
const char *name;
struct device_node *of_node;
+ struct samsung_pinctrl_drv_data *drvdata;
};
/**
--
1.7.12
^ permalink raw reply related
* [PATCH 07/16] pinctrl: samsung: Hold OF node of pin bank in bank struct
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
The node pointer will be used in extensions added by patches that will
follow.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-samsung.c | 1 +
drivers/pinctrl/pinctrl-samsung.h | 3 +++
2 files changed, 4 insertions(+)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 962320b..c988a4e 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -850,6 +850,7 @@ static int samsung_pinctrl_parse_dt_bank(struct samsung_pin_bank *bank,
return ret;
bank->nr_pins = val;
+ bank->of_node = np;
bank->name = np->name;
if (!of_find_property(np, "interrupt-controller", NULL)) {
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 72303f1..b7b74cc 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -111,6 +111,7 @@ struct samsung_pinctrl_drv_data;
* @eint_type: type of the external interrupt supported by the bank.
* @irq_base: starting controller local irq number of the bank.
* @name: name to be prefixed for each pin in this pin bank.
+ * @of_node: node of pin bank in device tree
*/
struct samsung_pin_bank {
u32 pctl_offset;
@@ -125,6 +126,8 @@ struct samsung_pin_bank {
u32 eint_offset;
u32 irq_base;
const char *name;
+
+ struct device_node *of_node;
};
/**
--
1.7.12
^ permalink raw reply related
* [PATCH 06/16] pinctrl: samsung: Parse bank-specific eint offset from DT
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
Some SoCs, like Exynos4x12, have non-sequential layout of EINT control
registers and so current way of calculating register addresses does not
work correctly for them.
This patch adds parsing of samsung,eint-offset property from bank nodes
and uses the read values instead of calculating the offsets from bank
index.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-exynos.c | 5 ++---
drivers/pinctrl/pinctrl-samsung.c | 5 +++++
drivers/pinctrl/pinctrl-samsung.h | 1 +
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 134fecf..340bfc2 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -146,7 +146,7 @@ static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw,
struct samsung_pin_bank *bank = d->ctrl->pin_banks;
struct exynos_geint_data *eint_data;
unsigned int nr_banks = d->ctrl->nr_banks, idx;
- unsigned int irq_base = 0, eint_offset = 0;
+ unsigned int irq_base = 0;
if (hw >= d->ctrl->nr_gint) {
dev_err(d->dev, "unsupported ext-gpio interrupt\n");
@@ -159,7 +159,6 @@ static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw,
if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins)))
break;
irq_base += bank->nr_pins;
- eint_offset += 4;
}
if (idx == nr_banks) {
@@ -175,7 +174,7 @@ static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw,
eint_data->bank = bank;
eint_data->pin = hw - irq_base;
- eint_data->eint_offset = eint_offset;
+ eint_data->eint_offset = bank->eint_offset;
return eint_data;
}
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index e828a0e..962320b 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -859,6 +859,11 @@ static int samsung_pinctrl_parse_dt_bank(struct samsung_pin_bank *bank,
bank->eint_type = EINT_TYPE_GPIO;
+ ret = of_property_read_u32(np, "samsung,eint-offset", &val);
+ if (ret)
+ return ret;
+ bank->eint_offset = val;
+
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index db1907c..72303f1 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -122,6 +122,7 @@ struct samsung_pin_bank {
u8 conpdn_width;
u8 pudpdn_width;
enum eint_type eint_type;
+ u32 eint_offset;
u32 irq_base;
const char *name;
};
--
1.7.12
^ permalink raw reply related
* [PATCH 05/16] pinctrl: exynos: Remove static SoC-specific data
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
The patch "pinctrl: samsung: Parse pin banks from DT" introduced parsing
SoC-specific data from device tree, so there is no need to keep the
previously used definitions in headers and source files.
This patch cleans up the pinctrl-exynos driver from unused
SoC-specific data.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-exynos.c | 96 -----------------------
drivers/pinctrl/pinctrl-exynos.h | 157 --------------------------------------
drivers/pinctrl/pinctrl-samsung.h | 1 -
3 files changed, 254 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index e3fa263..134fecf 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -504,102 +504,6 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
return 0;
}
-/* pin banks of exynos4210 pin-controller 0 */
-static struct samsung_pin_bank exynos4210_pin_banks0[] = {
- EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"),
- EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"),
- EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"),
- EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"),
- EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"),
- EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"),
- EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"),
- EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"),
- EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"),
- EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"),
- EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"),
- EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"),
- EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"),
- EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"),
- EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"),
- EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"),
-};
-
-/* pin banks of exynos4210 pin-controller 1 */
-static struct samsung_pin_bank exynos4210_pin_banks1[] = {
- EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"),
- EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"),
- EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"),
- EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"),
- EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"),
- EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"),
- EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"),
- EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"),
- EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"),
- EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"),
- EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"),
- EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"),
- EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"),
- EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"),
- EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"),
- EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"),
- EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"),
- EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"),
- EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"),
- EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"),
-};
-
-/* pin banks of exynos4210 pin-controller 2 */
-static struct samsung_pin_bank exynos4210_pin_banks2[] = {
- EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
- * three gpio/pin-mux/pinconfig controllers.
- */
-struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
- {
- /* pin-controller instance 0 data */
- .pin_banks = exynos4210_pin_banks0,
- .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0),
- .base = EXYNOS4210_GPIO_A0_START,
- .nr_pins = EXYNOS4210_GPIOA_NR_PINS,
- .nr_gint = EXYNOS4210_GPIOA_NR_GINT,
- .geint_con = EXYNOS_GPIO_ECON_OFFSET,
- .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
- .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
- .svc = EXYNOS_SVC_OFFSET,
- .eint_gpio_init = exynos_eint_gpio_init,
- .label = "exynos4210-gpio-ctrl0",
- }, {
- /* pin-controller instance 1 data */
- .pin_banks = exynos4210_pin_banks1,
- .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1),
- .base = EXYNOS4210_GPIOA_NR_PINS,
- .nr_pins = EXYNOS4210_GPIOB_NR_PINS,
- .nr_gint = EXYNOS4210_GPIOB_NR_GINT,
- .nr_wint = 32,
- .geint_con = EXYNOS_GPIO_ECON_OFFSET,
- .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
- .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
- .weint_con = EXYNOS_WKUP_ECON_OFFSET,
- .weint_mask = EXYNOS_WKUP_EMASK_OFFSET,
- .weint_pend = EXYNOS_WKUP_EPEND_OFFSET,
- .svc = EXYNOS_SVC_OFFSET,
- .eint_gpio_init = exynos_eint_gpio_init,
- .eint_wkup_init = exynos_eint_wkup_init,
- .label = "exynos4210-gpio-ctrl1",
- }, {
- /* pin-controller instance 2 data */
- .pin_banks = exynos4210_pin_banks2,
- .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2),
- .base = EXYNOS4210_GPIOA_NR_PINS +
- EXYNOS4210_GPIOB_NR_PINS,
- .nr_pins = EXYNOS4210_GPIOC_NR_PINS,
- .label = "exynos4210-gpio-ctrl2",
- },
-};
-
struct samsung_pin_ctrl_variant exynos4_pin_ctrl = {
.eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init,
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
index 31d0a06..a72cfc7 100644
--- a/drivers/pinctrl/pinctrl-exynos.h
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -17,133 +17,6 @@
* (at your option) any later version.
*/
-#define EXYNOS_GPIO_START(__gpio) ((__gpio##_START) + (__gpio##_NR))
-
-#define EXYNOS4210_GPIO_A0_NR (8)
-#define EXYNOS4210_GPIO_A1_NR (6)
-#define EXYNOS4210_GPIO_B_NR (8)
-#define EXYNOS4210_GPIO_C0_NR (5)
-#define EXYNOS4210_GPIO_C1_NR (5)
-#define EXYNOS4210_GPIO_D0_NR (4)
-#define EXYNOS4210_GPIO_D1_NR (4)
-#define EXYNOS4210_GPIO_E0_NR (5)
-#define EXYNOS4210_GPIO_E1_NR (8)
-#define EXYNOS4210_GPIO_E2_NR (6)
-#define EXYNOS4210_GPIO_E3_NR (8)
-#define EXYNOS4210_GPIO_E4_NR (8)
-#define EXYNOS4210_GPIO_F0_NR (8)
-#define EXYNOS4210_GPIO_F1_NR (8)
-#define EXYNOS4210_GPIO_F2_NR (8)
-#define EXYNOS4210_GPIO_F3_NR (6)
-#define EXYNOS4210_GPIO_J0_NR (8)
-#define EXYNOS4210_GPIO_J1_NR (5)
-#define EXYNOS4210_GPIO_K0_NR (7)
-#define EXYNOS4210_GPIO_K1_NR (7)
-#define EXYNOS4210_GPIO_K2_NR (7)
-#define EXYNOS4210_GPIO_K3_NR (7)
-#define EXYNOS4210_GPIO_L0_NR (8)
-#define EXYNOS4210_GPIO_L1_NR (3)
-#define EXYNOS4210_GPIO_L2_NR (8)
-#define EXYNOS4210_GPIO_Y0_NR (6)
-#define EXYNOS4210_GPIO_Y1_NR (4)
-#define EXYNOS4210_GPIO_Y2_NR (6)
-#define EXYNOS4210_GPIO_Y3_NR (8)
-#define EXYNOS4210_GPIO_Y4_NR (8)
-#define EXYNOS4210_GPIO_Y5_NR (8)
-#define EXYNOS4210_GPIO_Y6_NR (8)
-#define EXYNOS4210_GPIO_X0_NR (8)
-#define EXYNOS4210_GPIO_X1_NR (8)
-#define EXYNOS4210_GPIO_X2_NR (8)
-#define EXYNOS4210_GPIO_X3_NR (8)
-#define EXYNOS4210_GPIO_Z_NR (7)
-
-enum exynos4210_gpio_xa_start {
- EXYNOS4210_GPIO_A0_START = 0,
- EXYNOS4210_GPIO_A1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0),
- EXYNOS4210_GPIO_B_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1),
- EXYNOS4210_GPIO_C0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B),
- EXYNOS4210_GPIO_C1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0),
- EXYNOS4210_GPIO_D0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1),
- EXYNOS4210_GPIO_D1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0),
- EXYNOS4210_GPIO_E0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1),
- EXYNOS4210_GPIO_E1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0),
- EXYNOS4210_GPIO_E2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1),
- EXYNOS4210_GPIO_E3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2),
- EXYNOS4210_GPIO_E4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3),
- EXYNOS4210_GPIO_F0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4),
- EXYNOS4210_GPIO_F1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0),
- EXYNOS4210_GPIO_F2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1),
- EXYNOS4210_GPIO_F3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2),
-};
-
-enum exynos4210_gpio_xb_start {
- EXYNOS4210_GPIO_J0_START = 0,
- EXYNOS4210_GPIO_J1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0),
- EXYNOS4210_GPIO_K0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1),
- EXYNOS4210_GPIO_K1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0),
- EXYNOS4210_GPIO_K2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1),
- EXYNOS4210_GPIO_K3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2),
- EXYNOS4210_GPIO_L0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3),
- EXYNOS4210_GPIO_L1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0),
- EXYNOS4210_GPIO_L2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1),
- EXYNOS4210_GPIO_Y0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2),
- EXYNOS4210_GPIO_Y1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0),
- EXYNOS4210_GPIO_Y2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1),
- EXYNOS4210_GPIO_Y3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2),
- EXYNOS4210_GPIO_Y4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3),
- EXYNOS4210_GPIO_Y5_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4),
- EXYNOS4210_GPIO_Y6_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5),
- EXYNOS4210_GPIO_X0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6),
- EXYNOS4210_GPIO_X1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0),
- EXYNOS4210_GPIO_X2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1),
- EXYNOS4210_GPIO_X3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2),
-};
-
-enum exynos4210_gpio_xc_start {
- EXYNOS4210_GPIO_Z_START = 0,
-};
-
-#define EXYNOS4210_GPIO_A0_IRQ EXYNOS4210_GPIO_A0_START
-#define EXYNOS4210_GPIO_A1_IRQ EXYNOS4210_GPIO_A1_START
-#define EXYNOS4210_GPIO_B_IRQ EXYNOS4210_GPIO_B_START
-#define EXYNOS4210_GPIO_C0_IRQ EXYNOS4210_GPIO_C0_START
-#define EXYNOS4210_GPIO_C1_IRQ EXYNOS4210_GPIO_C1_START
-#define EXYNOS4210_GPIO_D0_IRQ EXYNOS4210_GPIO_D0_START
-#define EXYNOS4210_GPIO_D1_IRQ EXYNOS4210_GPIO_D1_START
-#define EXYNOS4210_GPIO_E0_IRQ EXYNOS4210_GPIO_E0_START
-#define EXYNOS4210_GPIO_E1_IRQ EXYNOS4210_GPIO_E1_START
-#define EXYNOS4210_GPIO_E2_IRQ EXYNOS4210_GPIO_E2_START
-#define EXYNOS4210_GPIO_E3_IRQ EXYNOS4210_GPIO_E3_START
-#define EXYNOS4210_GPIO_E4_IRQ EXYNOS4210_GPIO_E4_START
-#define EXYNOS4210_GPIO_F0_IRQ EXYNOS4210_GPIO_F0_START
-#define EXYNOS4210_GPIO_F1_IRQ EXYNOS4210_GPIO_F1_START
-#define EXYNOS4210_GPIO_F2_IRQ EXYNOS4210_GPIO_F2_START
-#define EXYNOS4210_GPIO_F3_IRQ EXYNOS4210_GPIO_F3_START
-#define EXYNOS4210_GPIO_J0_IRQ EXYNOS4210_GPIO_J0_START
-#define EXYNOS4210_GPIO_J1_IRQ EXYNOS4210_GPIO_J1_START
-#define EXYNOS4210_GPIO_K0_IRQ EXYNOS4210_GPIO_K0_START
-#define EXYNOS4210_GPIO_K1_IRQ EXYNOS4210_GPIO_K1_START
-#define EXYNOS4210_GPIO_K2_IRQ EXYNOS4210_GPIO_K2_START
-#define EXYNOS4210_GPIO_K3_IRQ EXYNOS4210_GPIO_K3_START
-#define EXYNOS4210_GPIO_L0_IRQ EXYNOS4210_GPIO_L0_START
-#define EXYNOS4210_GPIO_L1_IRQ EXYNOS4210_GPIO_L1_START
-#define EXYNOS4210_GPIO_L2_IRQ EXYNOS4210_GPIO_L2_START
-#define EXYNOS4210_GPIO_Z_IRQ EXYNOS4210_GPIO_Z_START
-
-#define EXYNOS4210_GPIOA_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3)
-#define EXYNOS4210_GPIOA_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3)
-#define EXYNOS4210_GPIOB_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3)
-#define EXYNOS4210_GPIOB_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2)
-#define EXYNOS4210_GPIOC_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z)
-
-/* External GPIO and wakeup interrupt related definitions */
-#define EXYNOS_GPIO_ECON_OFFSET 0x700
-#define EXYNOS_GPIO_EMASK_OFFSET 0x900
-#define EXYNOS_GPIO_EPEND_OFFSET 0xA00
-#define EXYNOS_WKUP_ECON_OFFSET 0xE00
-#define EXYNOS_WKUP_EMASK_OFFSET 0xF00
-#define EXYNOS_WKUP_EPEND_OFFSET 0xF40
-#define EXYNOS_SVC_OFFSET 0xB08
#define EXYNOS_EINT_FUNC 0xF
/* helpers to access interrupt service register */
@@ -163,36 +36,6 @@ enum exynos4210_gpio_xc_start {
#define EXYNOS_EINT_CON_LEN 4
#define EXYNOS_EINT_MAX_PER_BANK 8
-#define EXYNOS_EINT_NR_WKUP_EINT
-
-#define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id) \
- { \
- .pctl_offset = reg, \
- .pin_base = (__gpio##_START), \
- .nr_pins = (__gpio##_NR), \
- .func_width = 4, \
- .pud_width = 2, \
- .drv_width = 2, \
- .conpdn_width = 2, \
- .pudpdn_width = 2, \
- .eint_type = EINT_TYPE_NONE, \
- .name = id \
- }
-
-#define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id) \
- { \
- .pctl_offset = reg, \
- .pin_base = (__gpio##_START), \
- .nr_pins = (__gpio##_NR), \
- .func_width = 4, \
- .pud_width = 2, \
- .drv_width = 2, \
- .conpdn_width = 2, \
- .pudpdn_width = 2, \
- .eint_type = EINT_TYPE_GPIO, \
- .irq_base = (__gpio##_IRQ), \
- .name = id \
- }
/**
* struct exynos_geint_data: gpio eint specific data for irq_chip callbacks.
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 5d59ce6..db1907c 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -246,7 +246,6 @@ struct samsung_pmx_func {
};
/* list of all exported SoC specific data */
-extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
extern struct samsung_pin_ctrl_variant exynos4_pin_ctrl;
#endif /* __PINCTRL_SAMSUNG_H */
--
1.7.12
^ permalink raw reply related
* [PATCH 04/16] pinctrl: samsung: Parse pin banks from DT
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
Currently SoC-specific properties such as list of pin banks, register
offsets and bitfield sizes are being taken from static data structures
residing in pinctrl-exynos.c.
This patch modifies the pinctrl-samsung driver to parse all SoC-specific
data from device tree, which will allow to remove the static data
structures and facilitate adding of further SoC variants to the
pinctrl-samsung driver.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-exynos.c | 5 ++
drivers/pinctrl/pinctrl-samsung.c | 169 +++++++++++++++++++++++++++++++++++++-
drivers/pinctrl/pinctrl-samsung.h | 17 +++-
3 files changed, 187 insertions(+), 4 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index b4b58d4..e3fa263 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -599,3 +599,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
.label = "exynos4210-gpio-ctrl2",
},
};
+
+struct samsung_pin_ctrl_variant exynos4_pin_ctrl = {
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .eint_wkup_init = exynos_eint_wkup_init,
+};
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index c660fa5..e828a0e 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -46,6 +46,8 @@ struct pin_config {
{ "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
};
+static unsigned int pin_base = 0;
+
/* check if the selector is a valid pin group selector */
static int samsung_get_group_count(struct pinctrl_dev *pctldev)
{
@@ -602,6 +604,8 @@ static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev,
u32 function;
if (of_find_property(cfg_np, "interrupt-controller", NULL))
continue;
+ if (of_find_property(cfg_np, "gpio-controller", NULL))
+ continue;
ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np,
&drvdata->pctl, &pin_list, &npins);
@@ -778,6 +782,86 @@ static int __init samsung_gpiolib_unregister(struct platform_device *pdev,
static const struct of_device_id samsung_pinctrl_dt_match[];
+static int samsung_pinctrl_parse_dt_bank_type(struct samsung_pin_bank *bank,
+ struct device_node *np)
+{
+ struct samsung_pin_bank *type = np->data;
+ int ret;
+ u32 val;
+
+ if (type) {
+ *bank = *type;
+ return 0;
+ }
+
+ type = kzalloc(sizeof(*type), GFP_KERNEL);
+ if (!type)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(np, "samsung,func-width", &val);
+ if (ret)
+ return ret;
+ type->func_width = val;
+
+ ret = of_property_read_u32(np, "samsung,pud-width", &val);
+ if (!ret)
+ type->pud_width = val;
+
+ ret = of_property_read_u32(np, "samsung,drv-width", &val);
+ if (!ret)
+ type->drv_width = val;
+
+ ret = of_property_read_u32(np, "samsung,conpdn-width", &val);
+ if (!ret)
+ type->conpdn_width = val;
+
+ ret = of_property_read_u32(np, "samsung,pudpdn-width", &val);
+ if (!ret)
+ type->pudpdn_width = val;
+
+ *bank = *type;
+ np->data = type;
+
+ return 0;
+}
+
+static int samsung_pinctrl_parse_dt_bank(struct samsung_pin_bank *bank,
+ struct device_node *np)
+{
+ int ret;
+ u32 val;
+ struct device_node *type_np;
+
+ type_np = of_parse_phandle(np, "samsung,bank-type", 0);
+ if (!type_np)
+ return -EINVAL;
+
+ ret = samsung_pinctrl_parse_dt_bank_type(bank, type_np);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "samsung,pctl-offset", &val);
+ if (ret)
+ return ret;
+ bank->pctl_offset = val;
+
+ ret = of_property_read_u32(np, "samsung,pin-count", &val);
+ if (ret)
+ return ret;
+ bank->nr_pins = val;
+
+ bank->name = np->name;
+
+ if (!of_find_property(np, "interrupt-controller", NULL)) {
+ bank->eint_type = EINT_TYPE_NONE;
+ return 0;
+ }
+
+ bank->eint_type = EINT_TYPE_GPIO;
+
+ return 0;
+}
+
/* retrieve the soc specific data */
static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
struct platform_device *pdev)
@@ -785,6 +869,14 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
int id;
const struct of_device_id *match;
const struct device_node *node = pdev->dev.of_node;
+ struct device_node *bank_np;
+ struct samsung_pin_ctrl *ctrl;
+ struct samsung_pin_bank *banks, *b;
+ struct samsung_pin_ctrl_variant *variant;
+ unsigned int bank_cnt = 0;
+ unsigned int eint_cnt = 0;
+ u32 val;
+ int ret;
id = of_alias_get_id(pdev->dev.of_node, "pinctrl");
if (id < 0) {
@@ -792,7 +884,80 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
return NULL;
}
match = of_match_node(samsung_pinctrl_dt_match, node);
- return (struct samsung_pin_ctrl *)match->data + id;
+ variant = match->data;
+
+ for_each_child_of_node(node, bank_np) {
+ if (!of_find_property(bank_np, "gpio-controller", NULL))
+ continue;
+ ++bank_cnt;
+ }
+
+ if (!bank_cnt) {
+ dev_err(&pdev->dev, "no pin banks specified\n");
+ return NULL;
+ }
+
+ ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "failed to allocate soc data\n");
+ return NULL;
+ }
+
+ banks = devm_kzalloc(&pdev->dev,
+ bank_cnt * sizeof(*ctrl->pin_banks), GFP_KERNEL);
+ if (!banks) {
+ dev_err(&pdev->dev, "failed to allocate pin banks\n");
+ return NULL;
+ }
+
+ b = banks;
+ for_each_child_of_node(node, bank_np) {
+ if (!of_find_property(bank_np, "gpio-controller", NULL))
+ continue;
+ if (samsung_pinctrl_parse_dt_bank(b, bank_np))
+ return NULL;
+ b->pin_base = ctrl->nr_pins;
+ ctrl->nr_pins += b->nr_pins;
+ if (b->eint_type == EINT_TYPE_GPIO) {
+ b->irq_base = eint_cnt;
+ eint_cnt += b->nr_pins;
+ }
+ ++b;
+ }
+
+ if (eint_cnt) {
+ ret = of_property_read_u32(node, "samsung,geint-con", &val);
+ if (ret)
+ return NULL;
+ ctrl->geint_con = val;
+
+ ret = of_property_read_u32(node, "samsung,geint-mask", &val);
+ if (ret)
+ return NULL;
+ ctrl->geint_mask = val;
+
+ ret = of_property_read_u32(node, "samsung,geint-pend", &val);
+ if (ret)
+ return NULL;
+ ctrl->geint_pend = val;
+
+ ret = of_property_read_u32(node, "samsung,svc", &val);
+ if (ret)
+ return NULL;
+ ctrl->svc = val;
+
+ ctrl->eint_gpio_init = variant->eint_gpio_init;
+ }
+
+ ctrl->pin_banks = banks;
+ ctrl->nr_banks = bank_cnt;
+ ctrl->nr_gint = eint_cnt;
+ ctrl->label = node->name;
+ ctrl->eint_wkup_init = variant->eint_wkup_init;
+ ctrl->base = pin_base;
+ pin_base += ctrl->nr_pins;
+
+ return ctrl;
}
static int __devinit samsung_pinctrl_probe(struct platform_device *pdev)
@@ -860,7 +1025,7 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev)
static const struct of_device_id samsung_pinctrl_dt_match[] = {
{ .compatible = "samsung,pinctrl-exynos4210",
- .data = (void *)exynos4210_pin_ctrl },
+ .data = &exynos4_pin_ctrl },
{},
};
MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index b895693..5d59ce6 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -123,7 +123,19 @@ struct samsung_pin_bank {
u8 pudpdn_width;
enum eint_type eint_type;
u32 irq_base;
- char *name;
+ const char *name;
+};
+
+/**
+ * struct samsung_pin_ctrl_variant: represents a pin controller variant.
+ * @eint_gpio_init: platform specific callback to setup the external gpio
+ * interrupts for the controller.
+ * @eint_wkup_init: platform specific callback to setup the external wakeup
+ * interrupts for the controller.
+ */
+struct samsung_pin_ctrl_variant {
+ int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
+ int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
};
/**
@@ -168,7 +180,7 @@ struct samsung_pin_ctrl {
int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
- char *label;
+ const char *label;
};
/**
@@ -235,5 +247,6 @@ struct samsung_pmx_func {
/* list of all exported SoC specific data */
extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
+extern struct samsung_pin_ctrl_variant exynos4_pin_ctrl;
#endif /* __PINCTRL_SAMSUNG_H */
--
1.7.12
^ permalink raw reply related
* [PATCH 03/16] pinctrl: samsung: Detect and handle unsupported configuration types
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
This patch modifies the pinctrl-samsung driver to detect when width of a
bit field is set to zero (which means that such configuraton type is not
supported) and return an error instead of trying to modify an inexistent
register.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-samsung.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index dd108a9..c660fa5 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -391,6 +391,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
return -EINVAL;
}
+ if (!width)
+ return -EINVAL;
+
mask = (1 << width) - 1;
shift = pin_offset * width;
data = readl(reg_base + cfg_reg);
--
1.7.12
^ permalink raw reply related
* [PATCH 02/16] pinctrl: exynos: Parse wakeup-eint parameters from DT
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
This patch converts the pinctrl-exynos driver to parse wakeup interrupt
count and register offsets from device tree. It reduces the amount of
static platform-specific data and facilitates adding further SoC
variants to pinctrl-samsung driver.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
drivers/pinctrl/pinctrl-exynos.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 21362f4..b4b58d4 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -435,6 +435,8 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
struct device_node *np;
struct exynos_weint_data *weint_data;
int idx, irq;
+ u32 val;
+ int ret;
for_each_child_of_node(dev->of_node, np) {
if (of_match_node(exynos_wkup_irq_ids, np)) {
@@ -445,6 +447,26 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
if (!wkup_np)
return -ENODEV;
+ ret = of_property_read_u32(wkup_np, "samsung,weint-count", &val);
+ if (ret)
+ return -EINVAL;
+ d->ctrl->nr_wint = val;
+
+ ret = of_property_read_u32(wkup_np, "samsung,weint-con", &val);
+ if (ret)
+ return -EINVAL;
+ d->ctrl->weint_con = val;
+
+ ret = of_property_read_u32(wkup_np, "samsung,weint-mask", &val);
+ if (ret)
+ return -EINVAL;
+ d->ctrl->weint_mask = val;
+
+ ret = of_property_read_u32(wkup_np, "samsung,weint-pend", &val);
+ if (ret)
+ return -EINVAL;
+ d->ctrl->weint_pend = val;
+
d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint,
&exynos_wkup_irqd_ops, d);
if (!d->wkup_irqd) {
--
1.7.12
^ permalink raw reply related
* [PATCH 01/16] ARM: dts: exynos4210: Replace legacy GPIO bank nodes with pinctrl bank nodes
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349685556-23718-1-git-send-email-t.figa@samsung.com>
Seuqential patches from this series introduce SoC-specific data parsing
from device tree.
This patch removes legacy GPIO bank nodes from exynos4210.dtsi and
replaces them with nodes and properties required for these patches.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
---
arch/arm/boot/dts/exynos4210-pinctrl-banks.dtsi | 459 ++++++++++++++++++++++++
arch/arm/boot/dts/exynos4210-pinctrl.dtsi | 2 +
arch/arm/boot/dts/exynos4210.dtsi | 254 +------------
3 files changed, 474 insertions(+), 241 deletions(-)
create mode 100644 arch/arm/boot/dts/exynos4210-pinctrl-banks.dtsi
diff --git a/arch/arm/boot/dts/exynos4210-pinctrl-banks.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl-banks.dtsi
new file mode 100644
index 0000000..ec91f40
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4210-pinctrl-banks.dtsi
@@ -0,0 +1,459 @@
+/*
+ * Samsung's Exynos4210 SoC pinctrl banks device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung's Exynos4210 SoC pin banks are listed as device tree nodes
+ * in this file.
+ *
+ * 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.
+ */
+
+/ {
+ pinctrl-bank-types {
+ bank_off: bank-off {
+ samsung,reg-names = "func", "dat", "pud",
+ "drv", "conpdn", "pudpdn";
+ samsung,reg-params = <0x00 4>, <0x04 1>, <0x08 2>,
+ <0x0C 2>, <0x10 2>, <0x14 2>;
+ };
+
+ bank_alive: bank-alive {
+ samsung,reg-names = "func", "dat", "pud",
+ "drv";
+ samsung,reg-params = <0x00 4>, <0x04 1>, <0x08 2>,
+ <0x0C 2>;
+ };
+ };
+
+ pinctrl at 11400000 {
+ gpa0: gpa0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x000>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x00>;
+ #interrupt-cells = <2>;
+ };
+
+ gpa1: gpa1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x020>;
+ samsung,pin-count = <6>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x04>;
+ #interrupt-cells = <2>;
+ };
+
+ gpb: gpb {
+ gpio-controller;
+ samsung,pctl-offset = <0x040>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x08>;
+ #interrupt-cells = <2>;
+ };
+
+ gpc0: gpc0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x060>;
+ samsung,pin-count = <5>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x0C>;
+ #interrupt-cells = <2>;
+ };
+
+ gpc1: gpc1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x080>;
+ samsung,pin-count = <5>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x10>;
+ #interrupt-cells = <2>;
+ };
+
+ gpd0: gpd0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x0A0>;
+ samsung,pin-count = <4>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x14>;
+ #interrupt-cells = <2>;
+ };
+
+ gpd1: gpd1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x0C0>;
+ samsung,pin-count = <4>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x18>;
+ #interrupt-cells = <2>;
+ };
+
+ gpe0: gpe0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x0E0>;
+ samsung,pin-count = <5>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x1C>;
+ #interrupt-cells = <2>;
+ };
+
+ gpe1: gpe1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x100>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x20>;
+ #interrupt-cells = <2>;
+ };
+
+ gpe2: gpe2 {
+ gpio-controller;
+ samsung,pctl-offset = <0x120>;
+ samsung,pin-count = <6>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x24>;
+ #interrupt-cells = <2>;
+ };
+
+ gpe3: gpe3 {
+ gpio-controller;
+ samsung,pctl-offset = <0x140>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x28>;
+ #interrupt-cells = <2>;
+ };
+
+ gpe4: gpe4 {
+ gpio-controller;
+ samsung,pctl-offset = <0x160>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x2C>;
+ #interrupt-cells = <2>;
+ };
+
+ gpf0: gpf0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x180>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x30>;
+ #interrupt-cells = <2>;
+ };
+
+ gpf1: gpf1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x1A0>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x34>;
+ #interrupt-cells = <2>;
+ };
+
+ gpf2: gpf2 {
+ gpio-controller;
+ samsung,pctl-offset = <0x1C0>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x38>;
+ #interrupt-cells = <2>;
+ };
+
+ gpf3: gpf3 {
+ gpio-controller;
+ samsung,pctl-offset = <0x1E0>;
+ samsung,pin-count = <6>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x3C>;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pinctrl at 11000000 {
+ gpj0: gpj0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x000>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x00>;
+ #interrupt-cells = <2>;
+ };
+
+ gpj1: gpj1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x020>;
+ samsung,pin-count = <5>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x04>;
+ #interrupt-cells = <2>;
+ };
+
+ gpk0: gpk0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x040>;
+ samsung,pin-count = <7>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x08>;
+ #interrupt-cells = <2>;
+ };
+
+ gpk1: gpk1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x060>;
+ samsung,pin-count = <7>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x0C>;
+ #interrupt-cells = <2>;
+ };
+
+ gpk2: gpk2 {
+ gpio-controller;
+ samsung,pctl-offset = <0x080>;
+ samsung,pin-count = <7>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x10>;
+ #interrupt-cells = <2>;
+ };
+
+ gpk3: gpk3 {
+ gpio-controller;
+ samsung,pctl-offset = <0x0A0>;
+ samsung,pin-count = <7>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x14>;
+ #interrupt-cells = <2>;
+ };
+
+ gpl0: gpl0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x0C0>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x18>;
+ #interrupt-cells = <2>;
+ };
+
+ gpl1: gpl1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x0E0>;
+ samsung,pin-count = <3>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x1C>;
+ #interrupt-cells = <2>;
+ };
+
+ gpl2: gpl2 {
+ gpio-controller;
+ samsung,pctl-offset = <0x100>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,eint-offset = <0x20>;
+ #interrupt-cells = <2>;
+ };
+
+ gpy0: gpy0 {
+ gpio-controller;
+ samsung,pctl-offset = <0x120>;
+ samsung,pin-count = <6>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+
+ gpy1: gpy1 {
+ gpio-controller;
+ samsung,pctl-offset = <0x140>;
+ samsung,pin-count = <4>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+
+ gpy2: gpy2 {
+ gpio-controller;
+ samsung,pctl-offset = <0x160>;
+ samsung,pin-count = <6>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+
+ gpy3: gpy3 {
+ gpio-controller;
+ samsung,pctl-offset = <0x180>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+
+ gpy4: gpy4 {
+ gpio-controller;
+ samsung,pctl-offset = <0x1A0>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+
+ gpy5: gpy5 {
+ gpio-controller;
+ samsung,pctl-offset = <0x1C0>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+
+ gpy6: gpy6 {
+ gpio-controller;
+ samsung,pctl-offset = <0x1E0>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+
+ gpx0: gpx0 {
+ gpio-controller;
+ samsung,pctl-offset = <0xC00>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_alive>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,wkup-eint;
+ interrupt-parent = <&gic>;
+ interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+ <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>;
+ samsung,eint-offset = <0x00>;
+ #interrupt-cells = <2>;
+ };
+
+ gpx1: gpx1 {
+ gpio-controller;
+ samsung,pctl-offset = <0xC20>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_alive>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,wkup-eint;
+ interrupt-parent = <&gic>;
+ interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
+ <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
+ samsung,eint-offset = <0x04>;
+ #interrupt-cells = <2>;
+ };
+
+ gpx2: gpx2 {
+ gpio-controller;
+ samsung,pctl-offset = <0xC40>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_alive>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,wkup-eint;
+ samsung,eint-offset = <0x08>;
+ #interrupt-cells = <2>;
+ };
+
+ gpx3: gpx3 {
+ gpio-controller;
+ samsung,pctl-offset = <0xC60>;
+ samsung,pin-count = <8>;
+ samsung,bank-type = <&bank_alive>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ samsung,wkup-eint;
+ samsung,eint-offset = <0x0C>;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ pinctrl at 03860000 {
+ gpz: gpz {
+ gpio-controller;
+ samsung,pctl-offset = <0x000>;
+ samsung,pin-count = <7>;
+ samsung,bank-type = <&bank_off>;
+ #gpio-cells = <2>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
index b12cf27..94846d5 100644
--- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
@@ -14,6 +14,8 @@
* published by the Free Software Foundation.
*/
+/include/ "exynos4210-pinctrl-banks.dtsi"
+
/ {
pinctrl at 11400000 {
uart0_data: uart0-data {
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index 214c557..7f32a51 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -46,27 +46,28 @@
compatible = "samsung,pinctrl-exynos4210";
reg = <0x11400000 0x1000>;
interrupts = <0 47 0>;
- interrupt-controller;
- #interrupt-cells = <2>;
+ samsung,geint-con = <0x700>;
+ samsung,geint-mask = <0x900>;
+ samsung,geint-pend = <0xA00>;
+ samsung,svc = <0xB08>;
};
pinctrl_1: pinctrl at 11000000 {
compatible = "samsung,pinctrl-exynos4210";
reg = <0x11000000 0x1000>;
interrupts = <0 46 0>;
- interrupt-controller;
- #interrupt-cells = <2>;
+ samsung,geint-con = <0x700>;
+ samsung,geint-mask = <0x900>;
+ samsung,geint-pend = <0xA00>;
+ samsung,svc = <0xB08>;
- wakup_eint: wakeup-interrupt-controller {
+ wakeup-interrupt-controller {
compatible = "samsung,exynos4210-wakeup-eint";
interrupt-parent = <&gic>;
- interrupt-controller;
- #interrupt-cells = <2>;
- interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
- <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>,
- <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
- <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>,
- <0 32 0>;
+ interrupts = <0 32 0>;
+ samsung,weint-con = <0xE00>;
+ samsung,weint-mask = <0xF00>;
+ samsung,weint-pend = <0xF40>;
};
};
@@ -74,233 +75,4 @@
compatible = "samsung,pinctrl-exynos4210";
reg = <0x03860000 0x1000>;
};
-
- gpio-controllers {
- #address-cells = <1>;
- #size-cells = <1>;
- gpio-controller;
- ranges;
-
- gpa0: gpio-controller at 11400000 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400000 0x20>;
- #gpio-cells = <4>;
- };
-
- gpa1: gpio-controller at 11400020 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400020 0x20>;
- #gpio-cells = <4>;
- };
-
- gpb: gpio-controller at 11400040 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400040 0x20>;
- #gpio-cells = <4>;
- };
-
- gpc0: gpio-controller at 11400060 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400060 0x20>;
- #gpio-cells = <4>;
- };
-
- gpc1: gpio-controller at 11400080 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400080 0x20>;
- #gpio-cells = <4>;
- };
-
- gpd0: gpio-controller at 114000A0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x114000A0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpd1: gpio-controller at 114000C0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x114000C0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpe0: gpio-controller at 114000E0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x114000E0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpe1: gpio-controller at 11400100 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400100 0x20>;
- #gpio-cells = <4>;
- };
-
- gpe2: gpio-controller at 11400120 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400120 0x20>;
- #gpio-cells = <4>;
- };
-
- gpe3: gpio-controller at 11400140 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400140 0x20>;
- #gpio-cells = <4>;
- };
-
- gpe4: gpio-controller at 11400160 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400160 0x20>;
- #gpio-cells = <4>;
- };
-
- gpf0: gpio-controller at 11400180 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11400180 0x20>;
- #gpio-cells = <4>;
- };
-
- gpf1: gpio-controller at 114001A0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x114001A0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpf2: gpio-controller at 114001C0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x114001C0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpf3: gpio-controller at 114001E0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x114001E0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpj0: gpio-controller at 11000000 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000000 0x20>;
- #gpio-cells = <4>;
- };
-
- gpj1: gpio-controller at 11000020 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000020 0x20>;
- #gpio-cells = <4>;
- };
-
- gpk0: gpio-controller at 11000040 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000040 0x20>;
- #gpio-cells = <4>;
- };
-
- gpk1: gpio-controller at 11000060 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000060 0x20>;
- #gpio-cells = <4>;
- };
-
- gpk2: gpio-controller at 11000080 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000080 0x20>;
- #gpio-cells = <4>;
- };
-
- gpk3: gpio-controller at 110000A0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x110000A0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpl0: gpio-controller at 110000C0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x110000C0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpl1: gpio-controller at 110000E0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x110000E0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpl2: gpio-controller at 11000100 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000100 0x20>;
- #gpio-cells = <4>;
- };
-
- gpy0: gpio-controller at 11000120 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000120 0x20>;
- #gpio-cells = <4>;
- };
-
- gpy1: gpio-controller at 11000140 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000140 0x20>;
- #gpio-cells = <4>;
- };
-
- gpy2: gpio-controller at 11000160 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000160 0x20>;
- #gpio-cells = <4>;
- };
-
- gpy3: gpio-controller at 11000180 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000180 0x20>;
- #gpio-cells = <4>;
- };
-
- gpy4: gpio-controller at 110001A0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x110001A0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpy5: gpio-controller at 110001C0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x110001C0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpy6: gpio-controller at 110001E0 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x110001E0 0x20>;
- #gpio-cells = <4>;
- };
-
- gpx0: gpio-controller at 11000C00 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000C00 0x20>;
- #gpio-cells = <4>;
- };
-
- gpx1: gpio-controller at 11000C20 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000C20 0x20>;
- #gpio-cells = <4>;
- };
-
- gpx2: gpio-controller at 11000C40 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000C40 0x20>;
- #gpio-cells = <4>;
- };
-
- gpx3: gpio-controller at 11000C60 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x11000C60 0x20>;
- #gpio-cells = <4>;
- };
-
- gpz: gpio-controller at 03860000 {
- compatible = "samsung,exynos4-gpio";
- reg = <0x03860000 0x20>;
- #gpio-cells = <4>;
- };
- };
};
--
1.7.12
^ permalink raw reply related
* [PATCH 00/16] pinctrl: samsung: Usability and extensibiltiy improvements
From: Tomasz Figa @ 2012-10-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
This patch series is a work on improving usability and extensibiltiy of the
pinctrl-samsung driver. It consists of three main parts:
- moving SoC-specific data to device tree
- converting the driver to use one GPIO chip and one IRQ domain per pin bank
- introducing generic wake-up interrupt capability description
What the first part does is replacing static platform-specific data in
pinctrl-samsung driver with data dynamically parsed from device tree.
It aims at reducing the SoC-specific part of the driver and thus the
amount of modifications to driver sources when adding support for next
SoCs (like Exynos4x12).
In addition, it extends the description of SoC-specific attributes to cover all
mainlined Samsung SoCs, starting from s3c24xx and ending on latest Exynos5
series, with the exception of 4-bit banks with more than 8 pins on S3C64xx,
which will be covered by futher patch(es).
The second part attempts to simplify usage of the driver and fix several
problems of current implementation, in particular:
- Simplifies GPIO pin specification in device tree by using pin
namespace local to pin bank instead of local to pin controller, e.g.
gpios = <&gpj0 3 0>;
instead of
gpios = <&pinctrl0 115 0>;
- Simplifies GPIO interrupt specification in device tree by using
namespace local to pin bank (and equal to GPIO namespace), e.g.
interrupt-parent = <&gpj0>;
interrupts = <3 0>;
instead of
interrupt-parent = <&pinctrl0>;
interrupts = <115 0>;
- Simplifies internal GPIO pin to bank translation thanks to
correspondence of particular GPIO chips to pin banks. This allows
to remove the (costly in case of GPIO bit-banging drivers) lookup
over all banks to find the one that the pin is from.
Third part is focused on removing the static, hard-coded description of wake-up
interrupt controller and wake-up interrupt layout.
It defines a (mostly) generic (in scope of targetted SoCs) wake-up interrupt
layout specification format that allows to specify which pin banks support
wake-up interrupts and how they are handled (direct or multiplexed/chained).
See particular patches for more detailed descriptions and the last patch for
updated device tree bindings.
Tomasz Figa (16):
ARM: dts: exynos4210: Replace legacy GPIO bank nodes with pinctrl
bank nodes
pinctrl: exynos: Parse wakeup-eint parameters from DT
pinctrl: samsung: Detect and handle unsupported configuration types
pinctrl: samsung: Parse pin banks from DT
pinctrl: exynos: Remove static SoC-specific data
pinctrl: samsung: Parse bank-specific eint offset from DT
pinctrl: samsung: Hold OF node of pin bank in bank struct
pinctrl: samsung: Hold pointer to driver data in bank struct
pinctrl: exynos: Use one IRQ domain per pin bank
pinctrl: samsung: Do not pass gpio_chip to pin_to_reg_bank
pinctrl: samsung: Use one GPIO chip per pin bank
pinctrl: samsung: Use per-bank IRQ domain for wake-up interrupts
pinctrl: exynos: Set pin function to EINT in irq_set_type of wake-up
EINT
pinctrl: samsung: Parse offsets of particular registers from DT
pinctrl: samsung: Add GPIO to IRQ translation
Documentation: Update samsung-pinctrl device tree bindings
documentation
.../bindings/pinctrl/samsung-pinctrl.txt | 212 ++++++++--
arch/arm/boot/dts/exynos4210-pinctrl-banks.dtsi | 459 +++++++++++++++++++++
arch/arm/boot/dts/exynos4210-pinctrl.dtsi | 2 +
arch/arm/boot/dts/exynos4210.dtsi | 254 +-----------
drivers/pinctrl/pinctrl-exynos.c | 399 ++++++++----------
drivers/pinctrl/pinctrl-exynos.h | 184 +--------
drivers/pinctrl/pinctrl-samsung.c | 392 ++++++++++++++----
drivers/pinctrl/pinctrl-samsung.h | 87 ++--
8 files changed, 1205 insertions(+), 784 deletions(-)
create mode 100644 arch/arm/boot/dts/exynos4210-pinctrl-banks.dtsi
--
1.7.12
^ permalink raw reply
* Kernel panic in mxs_auart_irq_handle with latest kernel?
From: Uwe Kleine-König @ 2012-10-08 8:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121008080754.GW4625@n2100.arm.linux.org.uk>
Hello Russell,
On Mon, Oct 08, 2012 at 09:07:54AM +0100, Russell King - ARM Linux wrote:
> On Mon, Oct 08, 2012 at 09:45:47AM +0200, Uwe Kleine-K?nig wrote:
> > On Fri, Oct 05, 2012 at 11:58:26PM +0000, Subodh Nijsure wrote:
> > >
> > > On my MX28 based board with top of the Linus's git tree I am consistently getting following kernel panic, anybody else seen this?
> > > (I will start bisecting and see if I can find a reason this wknd)
> > >
> > > -Subodh
> > >
> > This dump is not complete, there is at least a line missing that reads
> >
> > [ $timestamp] pgd = ....
> >
> > It's a good habit to always provide the full info.
> >
> > > [ 9.700000] [00000118] *pgd=00000000
>
> Uwe, yes it is, it is the line above. It's saying that there is no
> pgd entry at address 0x118 (which is correct.)
I'm not sure I got you right, but show_pte() has:
printk(KERN_ALERT "pgd = %p\n", mm->pgd);
pgd = pgd_offset(mm, addr);
printk(KERN_ALERT "[%08lx] *pgd=%08llx",
addr, (long long)pgd_val(*pgd));
So there is indeed missing a line. I don't think it's essential here,
still I think in general it's advisable to let people know not to
shorten the output. Probably even let them post the complete kernel log.
(Isn't there an oops marker, too?)
> > > [ 9.700000] Internal error: Oops: 5 [#1] PREEMPT ARM
> > > [ 9.700000] Modules linked in:
> > > [ 9.700000] CPU: 0 Not tainted (3.6.0-11641-gbe4ae13-dirty #1)
> > > [ 9.700000] PC is at uart_insert_char+0x38/0x130
> > > [ 9.700000] LR is at mxs_auart_irq_handle+0x198/0x2b0
> > > [ 9.700000] pc : [<c025a3e0>] lr : [<c0261700>] psr: 40000093
> > > [ 9.700000] sp : c0549ea0 ip : 00000000 fp : 00000001
> > > [ 9.700000] r10: 00000000 r9 : c057e64e r8 : 00000020
> > > [ 9.700000] r7 : 00000000 r6 : 00080000 r5 : 00000000 r4 : c39566c0
> > > [ 9.700000] r3 : 00000020 r2 : 00000000 r1 : 00000000 r0 : 00000000
> > I don't see what should access the address 0x118 here, can you please
> > provide the output of
> >
> > objdump -d vmlinux | sed -nr '/^[0-9]{8} <uart_insert_char/,/^$/p'
>
> objdump -d vmlinux --start-addr=0xc025a3a8 | less
>
> will give you the disassembly starting at uart_insert_char().
>
> The faulting instruction is (which is below in the Code: line of the oops
> dump):
Ah, I already knew some time ago that the code is included in the dump,
I just did miss it because there are no address infos included there.
>
> e5973118
>
> It's an "ldr r3, [r7, #280] ; 0x118" instruction. r7 is zero, and the
> instruction has an pre-indexed offset of 0x118. _That_ is where 0x118
> is coming from.
obviously.
> The full code line is:
>
> 28: 1a000012 bne 0x78
> 2c: e59d2020 ldr r2, [sp, #32]
> 30: e5cd3006 strb r3, [sp, #6]
> 34: e5cd2007 strb r2, [sp, #7]
> 38: e5973118 ldr r3, [r7, #280] ; 0x118
>
> I suspect the problem is that the mxs serial driver is calling
> uart_insert_char() when the port has been closed by userland, which
> means there's no tty associated with it.
Thanks for your insights. At least my mail wasn't for nothing because I
learned again something about oopses.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Kernel panic in mxs_auart_irq_handle with latest kernel?
From: Russell King - ARM Linux @ 2012-10-08 8:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121008074547.GA18531@pengutronix.de>
On Mon, Oct 08, 2012 at 09:45:47AM +0200, Uwe Kleine-K?nig wrote:
> On Fri, Oct 05, 2012 at 11:58:26PM +0000, Subodh Nijsure wrote:
> >
> > On my MX28 based board with top of the Linus's git tree I am consistently getting following kernel panic, anybody else seen this?
> > (I will start bisecting and see if I can find a reason this wknd)
> >
> > -Subodh
> >
> This dump is not complete, there is at least a line missing that reads
>
> [ $timestamp] pgd = ....
>
> It's a good habit to always provide the full info.
>
> > [ 9.700000] [00000118] *pgd=00000000
Uwe, yes it is, it is the line above. It's saying that there is no
pgd entry at address 0x118 (which is correct.)
> > [ 9.700000] Internal error: Oops: 5 [#1] PREEMPT ARM
> > [ 9.700000] Modules linked in:
> > [ 9.700000] CPU: 0 Not tainted (3.6.0-11641-gbe4ae13-dirty #1)
> > [ 9.700000] PC is at uart_insert_char+0x38/0x130
> > [ 9.700000] LR is at mxs_auart_irq_handle+0x198/0x2b0
> > [ 9.700000] pc : [<c025a3e0>] lr : [<c0261700>] psr: 40000093
> > [ 9.700000] sp : c0549ea0 ip : 00000000 fp : 00000001
> > [ 9.700000] r10: 00000000 r9 : c057e64e r8 : 00000020
> > [ 9.700000] r7 : 00000000 r6 : 00080000 r5 : 00000000 r4 : c39566c0
> > [ 9.700000] r3 : 00000020 r2 : 00000000 r1 : 00000000 r0 : 00000000
> I don't see what should access the address 0x118 here, can you please
> provide the output of
>
> objdump -d vmlinux | sed -nr '/^[0-9]{8} <uart_insert_char/,/^$/p'
objdump -d vmlinux --start-addr=0xc025a3a8 | less
will give you the disassembly starting@uart_insert_char().
The faulting instruction is (which is below in the Code: line of the oops
dump):
e5973118
It's an "ldr r3, [r7, #280] ; 0x118" instruction. r7 is zero, and the
instruction has an pre-indexed offset of 0x118. _That_ is where 0x118
is coming from.
The full code line is:
28: 1a000012 bne 0x78
2c: e59d2020 ldr r2, [sp, #32]
30: e5cd3006 strb r3, [sp, #6]
34: e5cd2007 strb r2, [sp, #7]
38: e5973118 ldr r3, [r7, #280] ; 0x118
I suspect the problem is that the mxs serial driver is calling
uart_insert_char() when the port has been closed by userland, which
means there's no tty associated with it.
> Best regards
> Uwe
>
> > [ 9.700000] Flags: nZcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel
> > [ 9.700000] Control: 0005317f Table: 40004000 DAC: 00000017
> > [ 9.700000] Process swapper (pid: 0, stack limit = 0xc0548270)
> > [ 9.700000] Stack: (0xc0549ea0 to 0xc054a000)
> > [ 9.700000] 9ea0: c0554c00 00200002 00000000 c39566c0 00000000 0052006d 0052006d c0261700
> > [ 9.700000] 9ec0: 00000000 c0548000 c398f980 c0548000 00000000 00000000 000000d3 c057e64e
> > [ 9.700000] 9ee0: c387d700 c0063e74 ffffffff 20000093 00000002 c387d700 c0548000 00000000
> > [ 9.700000] 9f00: c0549f9c 40004000 41069265 40541cd8 00000000 c006403c 427c4747 00000002
> > [ 9.700000] 9f20: c0548000 c0548000 c387d700 c00662dc 000000d3 000000d3 00000000 c00637b0
> > [ 9.700000] 9f40: c0568748 c000ffec f5000000 c0549f68 c0587814 c0008778 c0010144 60000013
> > [ 9.700000] 9f60: ffffffff c000eda0 00000000 0005317f 0005217f 60000013 c0548000 c05875a8
> > [ 9.700000] 9f80: c0554300 c0644480 40004000 41069265 40541cd8 00000000 600000d3 c0549fb0
> > [ 9.700000] 9fa0: c0010138 c0010144 60000013 ffffffff 60000093 c0010308 c05500a8 c0587520
> > [ 9.700000] 9fc0: c0543150 c0522700 ffffffff ffffffff c05221d0 00000000 00000000 c0543150
> > [ 9.700000] 9fe0: 00000000 00053175 c055001c c0543120 c05542f4 40008040 00000000 00000000
> > [ 9.700000] [<c025a3e0>] (uart_insert_char+0x38/0x130) from [<c0261700>] (mxs_auart_irq_handle+0x198/0x2b0)
> > [ 9.700000] [<c0261700>] (mxs_auart_irq_handle+0x198/0x2b0) from [<c0063e74>] (handle_irq_event_percpu+0x50/0x1c4)
> > [ 9.700000] [<c0063e74>] (handle_irq_event_percpu+0x50/0x1c4) from [<c006403c>] (handle_irq_event+0x54/0x84)
> > [ 9.700000] [<c006403c>] (handle_irq_event+0x54/0x84) from [<c00662dc>] (handle_level_irq+0x98/0x14c)
> > [ 9.700000] [<c00662dc>] (handle_level_irq+0x98/0x14c) from [<c00637b0>] (generic_handle_irq+0x20/0x30)
> > [ 9.700000] [<c00637b0>] (generic_handle_irq+0x20/0x30) from [<c000ffec>] (handle_IRQ+0x30/0x84)
> > [ 9.700000] [<c000ffec>] (handle_IRQ+0x30/0x84) from [<c0008778>] (icoll_handle_irq+0x34/0x48)
> > [ 9.700000] [<c0008778>] (icoll_handle_irq+0x34/0x48) from [<c000eda0>] (__irq_svc+0x40/0x6c)
> > [ 9.700000] Exception stack(0xc0549f68 to 0xc0549fb0)
> > [ 9.700000] 9f60: 00000000 0005317f 0005217f 60000013 c0548000 c05875a8
> > [ 9.700000] 9f80: c0554300 c0644480 40004000 41069265 40541cd8 00000000 600000d3 c0549fb0
> > [ 9.700000] 9fa0: c0010138 c0010144 60000013 ffffffff
> > [ 9.700000] [<c000eda0>] (__irq_svc+0x40/0x6c) from [<c0010144>] (default_idle+0x38/0x40)
> > [ 9.700000] [<c0010144>] (default_idle+0x38/0x40) from [<c0010308>] (cpu_idle+0x9c/0xd4)
> > [ 9.700000] [<c0010308>] (cpu_idle+0x9c/0xd4) from [<c0522700>] (start_kernel+0x264/0x2a4)
> > [ 9.700000] [<c0522700>] (start_kernel+0x264/0x2a4) from [<40008040>] (0x40008040)
> > [ 9.700000] Code: 1a000012 e59d2020 e5cd3006 e5cd2007 (e5973118)
> > [ 9.700000] ---[ end trace 179ba7640a9ebb7c ]---
> > [ 9.700000] Kernel panic - not syncing: Fatal exception in interrupt
>
> --
> Pengutronix e.K. | Uwe Kleine-K?nig |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 0/9] ARM: dts/OMAP: Pinmux audio configuration for OMAP4+
From: Péter Ujfalusi @ 2012-10-08 8:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121005230354.GS3874@atomide.com>
On 10/06/2012 02:03 AM, Tony Lindgren wrote:
> * Peter Ujfalusi <peter.ujfalusi@ti.com> [121004 04:57]:
>> Hello,
>>
>> u-boot recently stopped configuring 'non essential' pin mux. This change leaves
>> the audio essential pins in non configured state which prevents the use of audio.
>> The following series makes sure that the needed pins are configured correctly by
>> the kernel on OMAP4 and OMAP5.
>>
>> Tony: can this series queued for 3.7?
>
> Let's see if that's possible to avoid mysterious bug reports
> of things not working.
>
> If we can't merge it, then it might be worth adding a warning
> that bails out early after some pin is checked or similar.
With new enough u-boot the twl6040 fails to probe (mux for nirq2 and power
GPIO is not configured) which leads to no audio on OMAP4/5.
Adding another warning - and check - does not going to help to clarify the
situation IMHO.
We can still enable the CONFIG_SYS_ENABLE_PADS_ALL in u-boot and recompile it,
but this is disabled as default and to be frank there is no guaranty that this
is going to be available let's say next week.
--
P?ter
^ permalink raw reply
* [PATCH 0/4] cpufreq: db8500: Use platform data to provide cpufreq table
From: Rafael J. Wysocki @ 2012-10-08 7:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPDyKFqqS4D4ZNDp3tFqE5t5iYOKCcaQYvyFsfGQa5U8bzWWag@mail.gmail.com>
On Wednesday 03 of October 2012 12:12:05 Ulf Hansson wrote:
> On 2 October 2012 13:45, Linus Walleij <linus.walleij@linaro.org> wrote:
> > On Fri, Sep 28, 2012 at 4:16 PM, Ulf Hansson <ulf.hansson@stericsson.com> wrote:
> >
> >> From: Ulf Hansson <ulf.hansson@linaro.org>
> >>
> >> Since the cpufreq table is dependant on the prmcu fw, it make sense to
> >> keep the table there. Moreover since the cpufreq is already a mfd child
> >> device added by the prcmu this make even more logic.
> >
> > Better there than elsewhere.
> >
> >> The next step after these patches will be to implement an "arm_clk" to be
> >> used from cpufreq to update the opp instead of using the prcmu opp API directly.
> >> This will then remove the last hard dependency to the prcmu API from cpufreq.
> >
> > Sounds like a plan.
> >
> > Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> >
> > Is this going to be merged through the cpufreq tree or the MFD tree?
>
> Good question! Actually I would prefer to go through Mike Turquette
> clock tree, if he feel it is OK of course.
> My idea is then get the Ack from Rafael for cpufreq patches and from
> Samuel for the mfd patches.
>
> The reason for doing this in a quite complicated manner is that my
> soon upcoming clock and mfd patches will functionality wise depend on
> these patches, and don't want to be sitting around and waiting for a
> new rc before being able to push the next series.
The cpufreq patches look good to me, please feel free to tag them as ACKed by me.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
^ permalink raw reply
* [PATCH v2 2/5] clk: exynos4: register clocks using common clock framework
From: Tomasz Figa @ 2012-10-08 7:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349629855-4962-3-git-send-email-thomas.abraham@linaro.org>
Hi Thomas,
The whole series looks much better now. Although there is still one more
thing from my comments to previous version unresolved, see the inline
comment.
On Monday 08 of October 2012 02:10:52 Thomas Abraham wrote:
> For legacy Exynos4 platforms, the available clocks are statically
> listed and then registered using the common clock framework. On device
> tree enabled exynos platfotms, the device tree is searched and all
> clock nodes found are registered. Support for Exynos4210 and
> Exynos4x12 platforms is included.
>
> Cc: Mike Turquette <mturquette@ti.com>
> Cc: Kukjin Kim <kgene.kim@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
> drivers/clk/samsung/Makefile | 1 +
> drivers/clk/samsung/clk-exynos4.c | 647
> +++++++++++++++++++++++++++++++++++++ 2 files changed, 648
> insertions(+), 0 deletions(-)
> create mode 100644 drivers/clk/samsung/clk-exynos4.c
>
[snip]
> + EXYNOS4_CLKSRC_MASK_CAM, 28, "sclk_csis"),
> + GATECLK(NULL, "sclk_cam0", "div_cam0", 0,
> + EXYNOS4_CLKSRC_MASK_CAM, 16, NULL),
> + GATECLK(NULL, "sclk_cam1", "div_cam1", 0,
> + EXYNOS4_CLKSRC_MASK_CAM, 20, NULL),
> + GATECLK("exynos4-fimc.0", "sclk_fimc", "div_fimc0", 0,
> + EXYNOS4_CLKSRC_MASK_CAM, 0, "sclk_fimc"),
> + GATECLK("exynos4-fimc.1", "sclk_fimc", "div_fimc1", 0,
> + EXYNOS4_CLKSRC_MASK_CAM, 4, "sclk_fimc"),
> + GATECLK("exynos4-fimc.2", "sclk_fimc", "div_fimc2", 0,
> + EXYNOS4_CLKSRC_MASK_CAM, 8, "sclk_fimc"),
> + GATECLK("exynos4-fimc.3", "sclk_fimc", "div_fimc3", 0,
> + EXYNOS4_CLKSRC_MASK_CAM, 12, "sclk_fimc"),
You cannot register more than one clock with the same platform name
(sclk_fimc). Shouldn't these names be appended with an index, just like
with div_fimc{0,1,2,3}?
Best regards,
--
Tomasz Figa
Samsung Poland R&D Center
^ permalink raw reply
* [PATCH] ARM: sort select statements alphanumerically
From: Russell King - ARM Linux @ 2012-10-08 7:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMPhdO-SuJwz4uN=1sQWtr3WOn656_M9iEGkMDjtOKTrsMUDpg@mail.gmail.com>
On Mon, Oct 08, 2012 at 10:50:00AM +0800, Eric Miao wrote:
> BTW, maybe we also need to sort the ARCH_XXX in alphanumeric order, so
> new ARCH will find a better place to live?
They should be sorted according to option text already - this is to
allow people using the configuration tool to easily find the right
option to select in that long list. That's something I did well
before arm-soc.
It looks pretty good at the moment, except for the following two:
bool "Cavium Networks CNS3XXX family"
bool "NXP LPC32XX"
^ permalink raw reply
* Kernel panic in mxs_auart_irq_handle with latest kernel?
From: Uwe Kleine-König @ 2012-10-08 7:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <B437D8FD67C39240BFA9DD878702A627EB4BD8@mx2.grid-net.com>
On Fri, Oct 05, 2012 at 11:58:26PM +0000, Subodh Nijsure wrote:
>
> On my MX28 based board with top of the Linus's git tree I am consistently getting following kernel panic, anybody else seen this?
> (I will start bisecting and see if I can find a reason this wknd)
>
> -Subodh
>
This dump is not complete, there is at least a line missing that reads
[ $timestamp] pgd = ....
It's a good habit to always provide the full info.
> [ 9.700000] [00000118] *pgd=00000000
> [ 9.700000] Internal error: Oops: 5 [#1] PREEMPT ARM
> [ 9.700000] Modules linked in:
> [ 9.700000] CPU: 0 Not tainted (3.6.0-11641-gbe4ae13-dirty #1)
> [ 9.700000] PC is at uart_insert_char+0x38/0x130
> [ 9.700000] LR is at mxs_auart_irq_handle+0x198/0x2b0
> [ 9.700000] pc : [<c025a3e0>] lr : [<c0261700>] psr: 40000093
> [ 9.700000] sp : c0549ea0 ip : 00000000 fp : 00000001
> [ 9.700000] r10: 00000000 r9 : c057e64e r8 : 00000020
> [ 9.700000] r7 : 00000000 r6 : 00080000 r5 : 00000000 r4 : c39566c0
> [ 9.700000] r3 : 00000020 r2 : 00000000 r1 : 00000000 r0 : 00000000
I don't see what should access the address 0x118 here, can you please
provide the output of
objdump -d vmlinux | sed -nr '/^[0-9]{8} <uart_insert_char/,/^$/p'
Best regards
Uwe
> [ 9.700000] Flags: nZcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel
> [ 9.700000] Control: 0005317f Table: 40004000 DAC: 00000017
> [ 9.700000] Process swapper (pid: 0, stack limit = 0xc0548270)
> [ 9.700000] Stack: (0xc0549ea0 to 0xc054a000)
> [ 9.700000] 9ea0: c0554c00 00200002 00000000 c39566c0 00000000 0052006d 0052006d c0261700
> [ 9.700000] 9ec0: 00000000 c0548000 c398f980 c0548000 00000000 00000000 000000d3 c057e64e
> [ 9.700000] 9ee0: c387d700 c0063e74 ffffffff 20000093 00000002 c387d700 c0548000 00000000
> [ 9.700000] 9f00: c0549f9c 40004000 41069265 40541cd8 00000000 c006403c 427c4747 00000002
> [ 9.700000] 9f20: c0548000 c0548000 c387d700 c00662dc 000000d3 000000d3 00000000 c00637b0
> [ 9.700000] 9f40: c0568748 c000ffec f5000000 c0549f68 c0587814 c0008778 c0010144 60000013
> [ 9.700000] 9f60: ffffffff c000eda0 00000000 0005317f 0005217f 60000013 c0548000 c05875a8
> [ 9.700000] 9f80: c0554300 c0644480 40004000 41069265 40541cd8 00000000 600000d3 c0549fb0
> [ 9.700000] 9fa0: c0010138 c0010144 60000013 ffffffff 60000093 c0010308 c05500a8 c0587520
> [ 9.700000] 9fc0: c0543150 c0522700 ffffffff ffffffff c05221d0 00000000 00000000 c0543150
> [ 9.700000] 9fe0: 00000000 00053175 c055001c c0543120 c05542f4 40008040 00000000 00000000
> [ 9.700000] [<c025a3e0>] (uart_insert_char+0x38/0x130) from [<c0261700>] (mxs_auart_irq_handle+0x198/0x2b0)
> [ 9.700000] [<c0261700>] (mxs_auart_irq_handle+0x198/0x2b0) from [<c0063e74>] (handle_irq_event_percpu+0x50/0x1c4)
> [ 9.700000] [<c0063e74>] (handle_irq_event_percpu+0x50/0x1c4) from [<c006403c>] (handle_irq_event+0x54/0x84)
> [ 9.700000] [<c006403c>] (handle_irq_event+0x54/0x84) from [<c00662dc>] (handle_level_irq+0x98/0x14c)
> [ 9.700000] [<c00662dc>] (handle_level_irq+0x98/0x14c) from [<c00637b0>] (generic_handle_irq+0x20/0x30)
> [ 9.700000] [<c00637b0>] (generic_handle_irq+0x20/0x30) from [<c000ffec>] (handle_IRQ+0x30/0x84)
> [ 9.700000] [<c000ffec>] (handle_IRQ+0x30/0x84) from [<c0008778>] (icoll_handle_irq+0x34/0x48)
> [ 9.700000] [<c0008778>] (icoll_handle_irq+0x34/0x48) from [<c000eda0>] (__irq_svc+0x40/0x6c)
> [ 9.700000] Exception stack(0xc0549f68 to 0xc0549fb0)
> [ 9.700000] 9f60: 00000000 0005317f 0005217f 60000013 c0548000 c05875a8
> [ 9.700000] 9f80: c0554300 c0644480 40004000 41069265 40541cd8 00000000 600000d3 c0549fb0
> [ 9.700000] 9fa0: c0010138 c0010144 60000013 ffffffff
> [ 9.700000] [<c000eda0>] (__irq_svc+0x40/0x6c) from [<c0010144>] (default_idle+0x38/0x40)
> [ 9.700000] [<c0010144>] (default_idle+0x38/0x40) from [<c0010308>] (cpu_idle+0x9c/0xd4)
> [ 9.700000] [<c0010308>] (cpu_idle+0x9c/0xd4) from [<c0522700>] (start_kernel+0x264/0x2a4)
> [ 9.700000] [<c0522700>] (start_kernel+0x264/0x2a4) from [<40008040>] (0x40008040)
> [ 9.700000] Code: 1a000012 e59d2020 e5cd3006 e5cd2007 (e5973118)
> [ 9.700000] ---[ end trace 179ba7640a9ebb7c ]---
> [ 9.700000] Kernel panic - not syncing: Fatal exception in interrupt
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Devicetree/Interrupts problem
From: Tony Prisk @ 2012-10-08 7:42 UTC (permalink / raw)
To: linux-arm-kernel
Hopefully someone can explain to me what is going wrong with this irq
implementation.
I am trying to convert the irq.c from arch-vt8500 to enable
multiplatform support but have run into a problem I don't quite
understand.
In arch-vt8500/irq.c I have:
vt8500_irq_domain = irq_domain_add_linear(node, 64,
&vt8500_irq_domain_ops, priv);
for (i=0; i<17; i++) {
irq = irq_create_mapping(vt8500_irq_domain, i);
printk("%s: create_mapping returned %d for i=%d\n", __func__, irq, i);
BUGON(i <= 0);
irq_set_chip_and_handler(irq, &vt8500_irq_chip, handle_level_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
I am (if I understand it correctly) creating mappings from hwirq to
linux irq numbers. This code is run twice (two interrupt controllers).
The printk spews out a bunch of messages basically indicating that
hwirq(d) was mapped to virq(d+1). virq(0) is invalid I believe so this
all makes sense.
The problem occurs when I set 'i<18' or greater in the for-loop. (It
should be 64 eventually).
When the combined total is >=36 it causes a problem with the timer
(which is on hwirq=36 of the first controller).
in arch-vt8500/timer.c:
timer_irq = irq_of_parse_and_map(np, 0);
...
if (setup_irq(timer_irq, &irq))
pr_err("%s: setup_irq failed for %s\n", __func__,
clockevent.name);
timer_irq = 36, which seems to be causing the problem - while trying to
initialize the timer it gives the 'setup_irq failed for ...", the timer
doesn't get setup and the kernel freezes during boot.
If I create a mapping for hwirq=36 before running the for-loop, it maps
hwirq=36 to virq=36, and everything is happy. It seems that if hwirq!
=virq that it causes problems. Same thing happens for every other
irq-generating device.
I guess it must be something obvious - anything jump out to anyone?
Regards
Tony P
^ permalink raw reply
* [PATCH 04/10] of/i2c: Add support for I2C_CLIENT_WAKE when booting with Device Tree
From: Lee Jones @ 2012-10-08 7:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <506F2334.1040009@gmail.com>
On Fri, 05 Oct 2012, Rob Herring wrote:
> On 10/05/2012 10:31 AM, Lee Jones wrote:
> > It's important for wakeup sources such as keyboards, power buttons
> > and the like to identify themselves as wakeup devices. Until now
> > this has not been possible when platforms are booting via Device
> > Tree.
>
> A similar feature from Olof already went in for 3.7.
Ah yes, I see it. Thanks Rob.
> > Cc: Rob Herring <rob.herring@calxeda.com>
> > Cc: devicetree-discuss at lists.ozlabs.org
> > Acked-by: Linus Walleij <linus.walleij@linaro.org>
> > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > ---
> > drivers/of/of_i2c.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
> > index 1e173f3..2f20019 100644
> > --- a/drivers/of/of_i2c.c
> > +++ b/drivers/of/of_i2c.c
> > @@ -61,6 +61,9 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
> > info.of_node = of_node_get(node);
> > info.archdata = &dev_ad;
> >
> > + if (of_get_property(node, "i2c-client-wake", NULL))
> > + info.flags |= I2C_CLIENT_WAKE;
> > +
> > request_module("%s%s", I2C_MODULE_PREFIX, info.type);
> >
> > result = i2c_new_device(adap, &info);
> >
--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH 2/2] ARM: Exynos4: Register clocks via common clock framework
From: Tomasz Figa @ 2012-10-08 7:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJuYYwQCPOFMnQrA-n42hQFtK3TXQtJSjkQZmVgh_4pqnMi8iw@mail.gmail.com>
On Monday 08 of October 2012 12:04:18 Thomas Abraham wrote:
> Hi Tomasz,
>
> On 3 October 2012 19:40, Tomasz Figa <t.figa@samsung.com> wrote:
> > Hi Chander, Thomas,
> >
> > I can see one more problem here.
> >
> > Based on the fact that sdhci-s3c driver receives only the endpoint gate
> > clock (hsmmc), doesn't the following setup make the driver unable to
> > change the frequency of this clock?
>
> The driver never changes the clock frequency of the core system clocks
> nor of the endpoint. There are internal dividers inside the sdhci
> controller which are divide to acheive required clock speed.
What is the use of sdhci_cmu_set_clock (which calls clk_set_rate) in sdhci-
s3c, then?
I think you are missing CLK_SET_RATE_PARENT flags in clocks of which rate
can be changed by the driver.
Best regards,
--
Tomasz Figa
Samsung Poland R&D Center
^ permalink raw reply
* [PATCH] MTD: atmel_nand: fix compile error when use avr32-atstk1006_defconfig
From: Josh Wu @ 2012-10-08 6:46 UTC (permalink / raw)
To: linux-arm-kernel
fixed the following compile error when use avr32 config:
drivers/mtd/nand/atmel_nand.c: In function 'pmecc_err_location':
drivers/mtd/nand/atmel_nand.c:639: error: implicit declaration of function 'writel_relaxed'
Since in ARCH avr32, there is no macro "writel_relaxed" defined. In this patch we use macro "writel" instead.
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
drivers/mtd/nand/atmel_nand_ecc.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
index 8a1e9a6..e87af84 100644
--- a/drivers/mtd/nand/atmel_nand_ecc.h
+++ b/drivers/mtd/nand/atmel_nand_ecc.h
@@ -129,8 +129,13 @@
#define pmerrloc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_PMERRLOC_##reg)
+#if defined(CONFIG_ARCH_AT91)
#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+#elif defined(CONFIG_AVR32)
+#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
+ writel((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+#endif
#define pmerrloc_readl_sigma_relaxed(addr, n) \
readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/2] ARM: Exynos4: Register clocks via common clock framework
From: Thomas Abraham @ 2012-10-08 6:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <506EFB06.7010201@gmail.com>
Hi Sylwester,
Thanks for reviewing this patch series.
On 6 October 2012 00:21, Sylwester Nawrocki
<sylvester.nawrocki@gmail.com> wrote:
> Hello,
>
> On 10/01/2012 02:09 PM, chander.kashyap at linaro.org wrote:
>> From: Thomas Abraham<thomas.abraham@linaro.org>
>>
>> Register clocks for Exynos4 platfotms using common clock framework.
>> Also included are set of helper functions for clock registration
>> that can be reused on other Samsung platforms as well.
>>
>> Cc: Mike Turquette<mturquette@linaro.org>
>> Cc: Kukjin Kim<kgene.kim@samsung.com>
>> Signed-off-by: Thomas Abraham<thomas.abraham@linaro.org>
>> ---
>> arch/arm/mach-exynos/Kconfig | 1 +
>> arch/arm/mach-exynos/common.h | 3 +
>> arch/arm/mach-exynos/mct.c | 11 +-
>> arch/arm/plat-samsung/Kconfig | 4 +-
>> drivers/clk/Makefile | 1 +
>> drivers/clk/clk.c | 12 +-
>> drivers/clk/samsung/Makefile | 6 +
>> drivers/clk/samsung/clk-exynos4.c | 585 +++++++++++++++++++++++++++++++++++++
>> drivers/clk/samsung/clk.c | 231 +++++++++++++++
>> drivers/clk/samsung/clk.h | 190 ++++++++++++
>> 10 files changed, 1037 insertions(+), 7 deletions(-)
>> create mode 100644 drivers/clk/samsung/Makefile
>> create mode 100644 drivers/clk/samsung/clk-exynos4.c
>> create mode 100644 drivers/clk/samsung/clk.c
>> create mode 100644 drivers/clk/samsung/clk.h
> ...
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index 56e4495..456c50b 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -1196,6 +1196,7 @@ EXPORT_SYMBOL_GPL(clk_set_parent);
>> int __clk_init(struct device *dev, struct clk *clk)
>> {
>> int i, ret = 0;
>> + u8 index;
>> struct clk *orphan;
>> struct hlist_node *tmp, *tmp2;
>>
>> @@ -1259,6 +1260,7 @@ int __clk_init(struct device *dev, struct clk *clk)
>> __clk_lookup(clk->parent_names[i]);
>> }
>>
>> +
>> clk->parent = __clk_init_parent(clk);
>>
>> /*
>> @@ -1298,11 +1300,13 @@ int __clk_init(struct device *dev, struct clk *clk)
>> * this clock
>> */
>> hlist_for_each_entry_safe(orphan, tmp, tmp2,&clk_orphan_list, child_node)
>> - for (i = 0; i< orphan->num_parents; i++)
>> - if (!strcmp(clk->name, orphan->parent_names[i])) {
>> + if (orphan->num_parents> 1) {
>> + index = orphan->ops->get_parent(orphan->hw);
>> + if (!strcmp(clk->name, orphan->parent_names[index]))
>> __clk_reparent(orphan, clk);
>> - break;
>> - }
>> + } else if (!strcmp(clk->name, orphan->parent_names[0])) {
>> + __clk_reparent(orphan, clk);
>> + }
>
> As this touches generic code it should rather be put into a separate patch,
> along with an explanation why such a change is needed.
There is fix for this in mainline now.
>
>>
>> /*
>> * optional platform-specific magic
>> diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
>> new file mode 100644
>> index 0000000..69487f7
>> --- /dev/null
>> +++ b/drivers/clk/samsung/Makefile
>> @@ -0,0 +1,6 @@
>> +#
>> +# Samsung Clock specific Makefile
>> +#
>> +
>> +obj-$(CONFIG_PLAT_SAMSUNG) += clk.o
>> +obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o
>> diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
>> new file mode 100644
>> index 0000000..74a6f03
>> --- /dev/null
>> +++ b/drivers/clk/samsung/clk-exynos4.c
>> @@ -0,0 +1,585 @@
>> +/*
>> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>> + * Copyright (c) 2012 Linaro Ltd.
>> + *
>> + * 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.
>> + *
>> + * Common Clock Framework support for all Exynos4 platforms
>> +*/
>> +
>> +#include<linux/clk.h>
>> +#include<linux/clkdev.h>
>> +#include<linux/io.h>
>> +#include<linux/clk-provider.h>
>> +
>> +#include<plat/pll.h>
>> +#include<plat/cpu.h>
>> +#include<mach/regs-clock.h>
>> +#include<mach/sysmmu.h>
>> +#include<plat/map-s5p.h>
>> +
>> +#include "clk.h"
>> +
>> +#define EXYNOS4_OP_MODE (S5P_VA_CHIPID + 8)
>> +
>> +static const char *pll_parent_names[] __initdata = { "fin_pll" };
>> +static const char *fin_pll_parents[] __initdata = { "xxti", "xusbxti" };
>> +static const char *mout_apll_parents[] __initdata = { "fin_pll", "fout_apll", };
>> +static const char *mout_mpll_parents[] __initdata = { "fin_pll", "fout_mpll", };
>> +static const char *mout_epll_parents[] __initdata = { "fin_pll", "fout_epll", };
>> +
>> +static const char *sclk_ampll_parents[] __initdata = {
>> + "mout_mpll", "sclk_apll", };
>> +
>> +static const char *sclk_evpll_parents[] __initdata = {
>> + "mout_epll", "mout_vpll", };
>> +
>> +static const char *mout_core_parents[] __initdata = {
>> + "mout_apll", "mout_mpll", };
>> +
>> +static const char *mout_mfc_parents[] __initdata = {
>> + "mout_mfc0", "mout_mfc1", };
>> +
>> +static const char *mout_dac_parents[] __initdata = {
>> + "mout_vpll", "sclk_hdmiphy", };
>> +
>> +static const char *mout_hdmi_parents[] __initdata = {
>> + "sclk_pixel", "sclk_hdmiphy", };
>> +
>> +static const char *mout_mixer_parents[] __initdata = {
>> + "sclk_dac", "sclk_hdmi", };
>> +
>> +static const char *group1_parents[] __initdata = {
>> + "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0",
>> + "none", "sclk_hdmiphy", "mout_mpll", "mout_epll",
>> + "mout_vpll" };
>> +
>> +static struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] = {
>> + FRATE_CLK(NULL, "xxti", NULL, CLK_IS_ROOT, 24000000),
>> + FRATE_CLK(NULL, "xusbxti", NULL, CLK_IS_ROOT, 24000000),
>> + FRATE_CLK(NULL, "sclk_hdmi24m", NULL, CLK_IS_ROOT, 24000000),
>> + FRATE_CLK(NULL, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000),
>> + FRATE_CLK(NULL, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000),
>> +};
>> +
>> +static struct samsung_mux_clock exynos4_mux_clks[] = {
>> + MUXCLK(NULL, "fin_pll", fin_pll_parents, 0,
>> + EXYNOS4_OP_MODE, 0, 1, 0),
>> + MUXCLK(NULL, "mout_apll", mout_apll_parents, 0,
>> + EXYNOS4_CLKSRC_CPU, 0, 1, 0),
>> + MUXCLK(NULL, "mout_epll", mout_epll_parents, 0,
>> + EXYNOS4_CLKSRC_TOP0, 4, 1, 0),
>> + MUXCLK(NULL, "mout_core", mout_core_parents, 0,
>> + EXYNOS4_CLKSRC_CPU, 16, 1, 0),
>> + MUXCLK(NULL, "mout_aclk_200", sclk_ampll_parents, 0,
>> + EXYNOS4_CLKSRC_TOP0, 12, 1, 0),
>> + MUXCLK(NULL, "mout_aclk_100", sclk_ampll_parents, 0,
>> + EXYNOS4_CLKSRC_TOP0, 16, 1, 0),
>> + MUXCLK(NULL, "mout_aclk_160", sclk_ampll_parents, 0,
>> + EXYNOS4_CLKSRC_TOP0, 20, 1, 0),
>> + MUXCLK(NULL, "mout_aclk_133", sclk_ampll_parents, 0,
>> + EXYNOS4_CLKSRC_TOP0, 24, 1, 0),
>> + MUXCLK("exynos4210-uart.0", "mout_uart0", group1_parents, 0,
>> + EXYNOS4_CLKSRC_PERIL0, 0, 4, 0),
>> + MUXCLK("exynos4210-uart.1", "mout_uart1", group1_parents, 0,
>> + EXYNOS4_CLKSRC_PERIL0, 4, 4, 0),
>> + MUXCLK("exynos4210-uart.2", "mout_uart2", group1_parents, 0,
>> + EXYNOS4_CLKSRC_PERIL0, 8, 4, 0),
>> + MUXCLK("exynos4210-uart.3", "mout_uart3", group1_parents, 0,
>> + EXYNOS4_CLKSRC_PERIL0, 12, 4, 0),
>> + MUXCLK("exynos4-sdhci.0", "mout_mmc0", group1_parents, 0,
>> + EXYNOS4_CLKSRC_FSYS, 0, 4, 0),
>> + MUXCLK("exynos4-sdhci.1", "mout_mmc1", group1_parents, 0,
>> + EXYNOS4_CLKSRC_FSYS, 4, 4, 0),
>> + MUXCLK("exynos4-sdhci.1", "mout_mmc2", group1_parents, 0,
>> + EXYNOS4_CLKSRC_FSYS, 8, 4, 0),
>> + MUXCLK("exynos4-sdhci.1", "mout_mmc3", group1_parents, 0,
>> + EXYNOS4_CLKSRC_FSYS, 12, 4, 0),
>> + MUXCLK("exynos4210-spi.0", "mout_spi0", group1_parents, 0,
>> + EXYNOS4_CLKSRC_PERIL1, 16, 4, 0),
>> + MUXCLK("exynos4210-spi.1", "mout_spi1", group1_parents, 0,
>> + EXYNOS4_CLKSRC_PERIL1, 20, 4, 0),
>> + MUXCLK("exynos4210-spi.2", "mout_spi2", group1_parents, 0,
>> + EXYNOS4_CLKSRC_PERIL1, 24, 4, 0),
>> + MUXCLK(NULL, "mout_sata", sclk_ampll_parents, 0,
>> + EXYNOS4_CLKSRC_FSYS, 24, 1, 0),
>> + MUXCLK(NULL, "mout_mfc0", sclk_ampll_parents, 0,
>> + EXYNOS4_CLKSRC_MFC, 0, 1, 0),
>> + MUXCLK(NULL, "mout_mfc1", sclk_evpll_parents, 0,
>> + EXYNOS4_CLKSRC_MFC, 4, 1, 0),
>> + MUXCLK("s5p-mfc", "mout_mfc", mout_mfc_parents, 0,
>> + EXYNOS4_CLKSRC_MFC, 8, 1, 0),
>> + MUXCLK("s5p-mipi-csis.0", "mout_csis0", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 24, 4, 0),
>> + MUXCLK("s5p-mipi-csis.1", "mout_csis1", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 28, 4, 0),
>> + MUXCLK(NULL, "mout_cam0", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 16, 4, 0),
>> + MUXCLK(NULL, "mout_cam1", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 20, 4, 0),
>> + MUXCLK("exynos4-fimc.0", "mout_fimc0", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 0, 4, 0),
>> + MUXCLK("exynos4-fimc.1", "mout_fimc1", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 4, 4, 0),
>> + MUXCLK("exynos4-fimc.2", "mout_fimc2", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 8, 4, 0),
>> + MUXCLK("exynos4-fimc.3", "mout_fimc3", group1_parents, 0,
>> + EXYNOS4_CLKSRC_CAM, 12, 4, 0),
>> + MUXCLK("exynos4-fb.0", "mout_fimd0", group1_parents, 0,
>> + EXYNOS4_CLKSRC_LCD0, 0, 4, 0),
>> + MUXCLK(NULL, "sclk_dac", mout_dac_parents, 0,
>> + EXYNOS4_CLKSRC_TV, 8, 1, 0),
>> + MUXCLK(NULL, "sclk_hdmi", mout_hdmi_parents, 0,
>> + EXYNOS4_CLKSRC_TV, 0, 1, 0),
>> + MUXCLK(NULL, "sclk_mixer", mout_mixer_parents, 0,
>> + EXYNOS4_CLKSRC_TV, 4, 1, 0),
>> +};
>> +
>> +static struct samsung_div_clock exynos4_div_clks[] = {
>> + DIVCLK(NULL, "sclk_apll", "mout_apll", 0,
>> + EXYNOS4_CLKDIV_CPU, 24, 3, 0),
>> + DIVCLK(NULL, "div_core", "mout_core", 0,
>> + EXYNOS4_CLKDIV_CPU, 0, 3, 0),
>> + DIVCLK(NULL, "armclk", "div_core", 0,
>> + EXYNOS4_CLKDIV_CPU, 28, 3, 0),
>> + DIVCLK(NULL, "aclk_200", "mout_aclk_200", 0,
>> + EXYNOS4_CLKDIV_TOP, 0, 3, 0),
>> + DIVCLK(NULL, "aclk_100", "mout_aclk_100", 0,
>> + EXYNOS4_CLKDIV_TOP, 4, 4, 0),
>> + DIVCLK(NULL, "aclk_160", "mout_aclk_160", 0,
>> + EXYNOS4_CLKDIV_TOP, 8, 3, 0),
>> + DIVCLK(NULL, "aclk_133", "mout_aclk_133", 0,
>> + EXYNOS4_CLKDIV_TOP, 12, 3, 0),
>> + DIVCLK("exynos4210-uart.0", "div_uart0", "mout_uart0", 0,
>> + EXYNOS4_CLKDIV_PERIL0, 0, 4, 0),
>> + DIVCLK("exynos4210-uart.1", "div_uart1", "mout_uart1", 0,
>> + EXYNOS4_CLKDIV_PERIL0, 4, 4, 0),
>> + DIVCLK("exynos4210-uart.2", "div_uart2", "mout_uart2", 0,
>> + EXYNOS4_CLKDIV_PERIL0, 8, 4, 0),
>> + DIVCLK("exynos4210-uart.3", "div_uart3", "mout_uart3", 0,
>> + EXYNOS4_CLKDIV_PERIL0, 12, 4, 0),
>> + DIVCLK("exynos4-sdhci.0", "div_mmc0", "mout_mmc0", 0,
>> + EXYNOS4_CLKDIV_FSYS1, 0, 4, 0),
>> + DIVCLK("exynos4-sdhci.0", "div_mmc0_pre", "div_mmc0", 0,
>> + EXYNOS4_CLKDIV_FSYS1, 8, 8, 0),
>> + DIVCLK("exynos4-sdhci.1", "div_mmc1", "mout_mmc1", 0,
>> + EXYNOS4_CLKDIV_FSYS1, 16, 4, 0),
>> + DIVCLK("exynos4-sdhci.1", "div_mmc1_pre", "div_mmc1", 0,
>> + EXYNOS4_CLKDIV_FSYS1, 24, 8, 0),
>> + DIVCLK("exynos4-sdhci.2", "div_mmc2", "mout_mmc2", 0,
>> + EXYNOS4_CLKDIV_FSYS2, 0, 4, 0),
>> + DIVCLK("exynos4-sdhci.2", "div_mmc2_pre", "div_mmc2", 0,
>> + EXYNOS4_CLKDIV_FSYS2, 8, 8, 0),
>> + DIVCLK("exynos4-sdhci.3", "div_mmc3", "mout_mmc3", 0,
>> + EXYNOS4_CLKDIV_FSYS2, 16, 4, 0),
>> + DIVCLK("exynos4-sdhci.3", "div_mmc3_pre", "div_mmc3", 0,
>> + EXYNOS4_CLKDIV_FSYS2, 24, 8, 0),
>> + DIVCLK("exynos4210-spi.0", "div_spi0", "mout_spi0", 0,
>> + EXYNOS4_CLKDIV_PERIL1, 0, 4, 0),
>> + DIVCLK("exynos4210-spi.1", "div_spi1", "mout_spi1", 0,
>> + EXYNOS4_CLKDIV_PERIL1, 16, 4, 0),
>> + DIVCLK("exynos4210-spi.2", "div_spi2", "mout_spi2", 0,
>> + EXYNOS4_CLKDIV_PERIL2, 0, 4, 0),
>> + DIVCLK("exynos4210-spi.0", "div_spi0_pre", "div_spi0", 0,
>> + EXYNOS4_CLKDIV_PERIL1, 8, 8, 0),
>> + DIVCLK("exynos4210-spi.1", "div_spi1_pre", "div_spi1", 0,
>> + EXYNOS4_CLKDIV_PERIL1, 24, 8, 0),
>> + DIVCLK("exynos4210-spi.2", "div_spi2_pre", "div_spi2", 0,
>> + EXYNOS4_CLKDIV_PERIL2, 8, 8, 0),
>> + DIVCLK(NULL, "div_sata", "mout_sata", 0,
>> + EXYNOS4_CLKDIV_FSYS0, 20, 4, 0),
>> + DIVCLK("s5p-mfc", "div_mfc", "mout_mfc", 0,
>> + EXYNOS4_CLKDIV_MFC, 0, 4, 0),
>> + DIVCLK("s5p-mipi-csis.0", "div_csis0", "mout_csis0", 0,
>> + EXYNOS4_CLKDIV_CAM, 24, 4, 0),
>> + DIVCLK("s5p-mipi-csis.1", "div_csis1", "mout_csis1", 0,
>> + EXYNOS4_CLKDIV_CAM, 28, 4, 0),
>> + DIVCLK(NULL, "div_cam0", "mout_cam0", 0,
>> + EXYNOS4_CLKDIV_CAM, 16, 4, 0),
>> + DIVCLK(NULL, "div_cam1", "mout_cam1", 0,
>> + EXYNOS4_CLKDIV_CAM, 20, 4, 0),
>> + DIVCLK("exynos4-fimc.0", "div_fimc0", "mout_fimc0", 0,
>> + EXYNOS4_CLKDIV_CAM, 0, 4, 0),
>> + DIVCLK("exynos4-fimc.1", "div_fimc1", "mout_fimc1", 0,
>> + EXYNOS4_CLKDIV_CAM, 4, 4, 0),
>> + DIVCLK("exynos4-fimc.2", "div_fimc2", "mout_fimc2", 0,
>> + EXYNOS4_CLKDIV_CAM, 4, 4, 0),
>> + DIVCLK("exynos4-fimc.3", "div_fimc3", "mout_fimc3", 0,
>> + EXYNOS4_CLKDIV_CAM, 4, 4, 0),
>> + DIVCLK("exynos4-fb.0", "div_fimd0", "mout_fimd0", 0,
>> + EXYNOS4_CLKDIV_LCD0, 0, 4, 0),
>> + DIVCLK(NULL, "sclk_pixel", "mout_vpll", 0,
>> + EXYNOS4_CLKDIV_TV, 0, 4, 0),
>> +};
>> +
>> +struct samsung_gate_clock exynos4_gate_clks[] = {
>> + GATECLK("exynos4210-uart.0", "uart0", "aclk_100", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKGATE_IP_PERIL, 0, "uart"),
>> + GATECLK("exynos4210-uart.1", "uart1", "aclk_100", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKGATE_IP_PERIL, 1, "uart"),
>> + GATECLK("exynos4210-uart.2", "uart2", "aclk_100", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKGATE_IP_PERIL, 2, "uart"),
>> + GATECLK("exynos4210-uart.3", "uart3", "aclk_100", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKGATE_IP_PERIL, 3, "uart"),
>> + GATECLK("exynos4210-uart.4", "uart4", "aclk_100", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKGATE_IP_PERIL, 4, "uart"),
>> + GATECLK("exynos4210-uart.5", "uart5", "aclk_100", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKGATE_IP_PERIL, 5, "uart"),
>> + GATECLK("exynos4210-uart.0", "uclk0", "div_uart0", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKSRC_MASK_PERIL0, 0, "clk_uart_baud0"),
>> + GATECLK("exynos4210-uart.1", "uclk1", "div_uart1", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKSRC_MASK_PERIL0, 4, "clk_uart_baud0"),
>> + GATECLK("exynos4210-uart.2", "uclk2", "div_uart2", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKSRC_MASK_PERIL0, 8, "clk_uart_baud0"),
>> + GATECLK("exynos4210-uart.3", "uclk3", "div_uart3", CLK_SET_RATE_PARENT,
>> + EXYNOS4_CLKSRC_MASK_PERIL0, 12, "clk_uart_baud0"),
>> + GATECLK(NULL, "timers", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 24, NULL),
>> + GATECLK("s5p-mipi-csis.0", "csis", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 5, NULL),
>> + GATECLK(NULL, "jpeg", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 6, NULL),
>> + GATECLK("exynos4-fimc.0", "fimc0", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 0, "fimc"),
>> + GATECLK("exynos4-fimc.1", "fimc1", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 1, "fimc"),
>> + GATECLK("exynos4-fimc.2", "fimc2", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 2, "fimc"),
>> + GATECLK("exynos4-fimc.3", "fimc3", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 3, "fimc"),
>> + GATECLK("exynos4-sdhci.0", "hsmmc0", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 5, "hsmmc"),
>> + GATECLK("exynos4-sdhci.1", "hsmmc1", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 6, "hsmmc"),
>> + GATECLK("exynos4-sdhci.2", "hsmmc2", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 7, "hsmmc"),
>> + GATECLK("exynos4-sdhci.3", "hsmmc3", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 8, "hsmmc"),
>> + GATECLK(NULL, "dwmmc", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 9, NULL),
>> + GATECLK("s5p-sdo", "dac", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_TV, 2, NULL),
>> + GATECLK("s5p-mixer", "mixer", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_TV, 1, NULL),
>> + GATECLK("s5p-mixer", "vp", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_TV, 0, NULL),
>> + GATECLK("exynos4-hdmi", "hdmi", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_TV, 3, NULL),
>> + GATECLK("exynos4-hdmi", "hdmiphy", "aclk_160", 0,
>> + S5P_HDMI_PHY_CONTROL, 0, NULL),
>> + GATECLK("s5p-sdo", "dacphy", "aclk_160", 0,
>> + S5P_DAC_PHY_CONTROL, 0, NULL),
>> + GATECLK(NULL, "adc", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 15, NULL),
>> + GATECLK(NULL, "keypad", "aclk_100", 0,
>> + EXYNOS4210_CLKGATE_IP_PERIR, 16, NULL),
>> + GATECLK(NULL, "rtc", "aclk_100", 0,
>> + EXYNOS4210_CLKGATE_IP_PERIR, 15, NULL),
>> + GATECLK(NULL, "watchdog", "aclk_100", 0,
>> + EXYNOS4210_CLKGATE_IP_PERIR, 14, NULL),
>> + GATECLK(NULL, "usbhost", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 12, NULL),
>> + GATECLK(NULL, "otg", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 13, NULL),
>> + GATECLK("exynos4210-spi.0", "spi0", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 16, "spi"),
>> + GATECLK("exynos4210-spi.1", "spi1", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 17, "spi"),
>> + GATECLK("exynos4210-spi.2", "spi2", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 18, "spi"),
>> + GATECLK("samsung-i2s.0", "iis0", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 19, "iis"),
>> + GATECLK("samsung-i2s.1", "iis1", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 20, "iis"),
>> + GATECLK("samsung-i2s.2", "iis2", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 21, "iis"),
>> + GATECLK("samsung-ac97", "ac97", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 27, NULL),
>> + GATECLK("s5p-mfc", "mfc", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_MFC, 0, NULL),
>> + GATECLK("s3c2440-i2c.0", "i2c0", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 6, "i2c"),
>> + GATECLK("s3c2440-i2c.1", "i2c1", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 7, "i2c"),
>> + GATECLK("s3c2440-i2c.2", "i2c2", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 8, "i2c"),
>> + GATECLK("s3c2440-i2c.3", "i2c3", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 9, "i2c"),
>> + GATECLK("s3c2440-i2c.4", "i2c4", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 10, "i2c"),
>> + GATECLK("s3c2440-i2c.5", "i2c5", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 11, "i2c"),
>> + GATECLK("s3c2440-i2c.6", "i2c6", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 12, "i2c"),
>> + GATECLK("s3c2440-i2c.7", "i2c7", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 13, "i2c"),
>> + GATECLK("s3c2440-hdmiphy-i2c", "i2c", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_PERIL, 14, NULL),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(mfc_l, 0), "sysmmu0", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_MFC, 1, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(mfc_r, 1), "sysmmu1", "aclk_100", 0,
>> + EXYNOS4_CLKGATE_IP_MFC, 2, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(tv, 2), "sysmmu2", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_TV, 4, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(jpeg, 3), "sysmmu3", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 11, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(rot, 4), "sysmmu4", "aclk_200", 0,
>> + EXYNOS4210_CLKGATE_IP_IMAGE, 4, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc0, 5), "sysmmu5", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 7, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc1, 6), "sysmmu6", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 8, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc2, 7), "sysmmu7", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 9, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc3, 8), "sysmmu8", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_CAM, 10, "sysmmu"),
>> + GATECLK(SYSMMU_CLOCK_DEVNAME(fimd, 10), "sysmmu10", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_LCD0, 4, "sysmmu"),
>> + GATECLK("dma-pl330.0", "dma0", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 0, "dma"),
>> + GATECLK("dma-pl330.1", "dma1", "aclk_133", 0,
>> + EXYNOS4_CLKGATE_IP_FSYS, 1, "dma"),
>> + GATECLK("exynos4-fb.0", "fimd", "aclk_160", 0,
>> + EXYNOS4_CLKGATE_IP_LCD0, 0, "lcd"),
>> + GATECLK("exynos4210-spi.0", "sclk_spi0", "div_spi0_pre", 0,
>> + EXYNOS4_CLKSRC_MASK_PERIL1, 16, "spi_busclk0"),
>> + GATECLK("exynos4210-spi.1", "sclk_spi1", "div_spi1_pre", 0,
>> + EXYNOS4_CLKSRC_MASK_PERIL1, 20, "spi_busclk0"),
>> + GATECLK("exynos4210-spi.2", "sclk_spi2", "div_spi2_pre", 0,
>> + EXYNOS4_CLKSRC_MASK_PERIL1, 24, "spi_busclk0"),
>> + GATECLK("exynos4-sdhci.0", "sclk_mmc0", "div_mmc0_pre", 0,
>> + EXYNOS4_CLKSRC_MASK_FSYS, 0, "mmc_busclk.2"),
>> + GATECLK("exynos4-sdhci.1", "sclk_mmc1", "div_mmc1_pre", 0,
>> + EXYNOS4_CLKSRC_MASK_FSYS, 4, "mmc_busclk.2"),
>> + GATECLK("exynos4-sdhci.2", "sclk_mmc2", "div_mmc2_pre", 0,
>> + EXYNOS4_CLKSRC_MASK_FSYS, 8, "mmc_busclk.2"),
>> + GATECLK("exynos4-sdhci.3", "sclk_mmc3", "div_mmc3_pre", 0,
>> + EXYNOS4_CLKSRC_MASK_FSYS, 12, "mmc_busclk.2"),
>> + GATECLK("s5p-mipi-csis.0", "sclk_csis0", "div_csis0", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 24, "sclk_csis"),
>> + GATECLK("s5p-mipi-csis.1", "sclk_csis1", "div_csis1", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 28, "sclk_csis"),
>> + GATECLK(NULL, "sclk_cam0", "div_cam0", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 16, NULL),
>> + GATECLK(NULL, "sclk_cam1", "div_cam1", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 20, NULL),
>> + GATECLK("exynos4-fimc.0", "sclk_fimc", "div_fimc0", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 0, "sclk_fimc"),
>> + GATECLK("exynos4-fimc.1", "sclk_fimc", "div_fimc1", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 4, "sclk_fimc"),
>> + GATECLK("exynos4-fimc.2", "sclk_fimc", "div_fimc2", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 8, "sclk_fimc"),
>> + GATECLK("exynos4-fimc.3", "sclk_fimc", "div_fimc3", 0,
>> + EXYNOS4_CLKSRC_MASK_CAM, 12, "sclk_fimc"),
>> + GATECLK("exynos4-fb.0", "sclk_fimd", "div_fimd0", 0,
>> + EXYNOS4_CLKSRC_MASK_LCD0, 0, "sclk_fimd"),
>> +};
>> +
>> +/* register clock common to all Exynos4 platforms */
>> +void __init exynos4_clk_init(void)
>> +{
>> + samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks,
>> + ARRAY_SIZE(exynos4_fixed_rate_clks));
>> + samsung_clk_register_mux(exynos4_mux_clks,
>> + ARRAY_SIZE(exynos4_mux_clks));
>> + samsung_clk_register_div(exynos4_div_clks,
>> + ARRAY_SIZE(exynos4_div_clks));
>> + samsung_clk_register_gate(exynos4_gate_clks,
>> + ARRAY_SIZE(exynos4_gate_clks));
>> +}
> ...
>> diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
>> new file mode 100644
>> index 0000000..65156b9
>> --- /dev/null
>> +++ b/drivers/clk/samsung/clk.c
>> @@ -0,0 +1,231 @@
>> +/*
>> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>> + * Copyright (c) 2012 Linaro Ltd.
>> + *
>> + * 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 file includes utility functions to register clocks to common
>> + * clock framework for Samsung platforms. This includes an implementation
>> + * of Samsung 'pll type' clock to represent the implementation of the
>> + * pll found on Samsung platforms. In addition to that, utility functions
>> + * to register mux, div, gate and fixed rate types of clocks are included.
>> +*/
>> +
>> +#include "clk.h"
>> +
>> +static DEFINE_SPINLOCK(lock);
>> +
>> +#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
>> +
>> +/* determine the output clock speed of the pll */
>> +static unsigned long samsung_clk_pll_recalc_rate(struct clk_hw *hw,
>> + unsigned long parent_rate)
>> +{
>> + struct samsung_clk_pll *clk_pll = to_clk_pll(hw);
>> +
>> + if (clk_pll->get_rate)
>> + return to_clk_pll(hw)->get_rate(parent_rate);
>> +
>> + return 0;
>> +}
>> +
>> +/* round operation not supported */
>> +static long samsung_clk_pll_round_rate(struct clk_hw *hw, unsigned long drate,
>> + unsigned long *prate)
>> +{
>> + return samsung_clk_pll_recalc_rate(hw, *prate);
>> +}
>> +
>> +/* set the clock output rate of the pll */
>> +static int samsung_clk_pll_set_rate(struct clk_hw *hw, unsigned long drate,
>> + unsigned long prate)
>> +{
>> + struct samsung_clk_pll *clk_pll = to_clk_pll(hw);
>> +
>> + if (clk_pll->set_rate)
>> + return to_clk_pll(hw)->set_rate(drate);
>> +
>> + return 0;
>> +}
>> +
>> +/* clock operations for samsung pll clock type */
>> +static const struct clk_ops samsung_clk_pll_ops = {
>> + .recalc_rate = samsung_clk_pll_recalc_rate,
>> + .round_rate = samsung_clk_pll_round_rate,
>> + .set_rate = samsung_clk_pll_set_rate,
>> +};
>> +
>> +/* register a samsung pll type clock */
>> +void __init samsung_clk_register_pll(const char *name, const char **pnames,
>> + int (*set_rate)(unsigned long rate),
>> + unsigned long (*get_rate)(unsigned long rate))
>> +{
>> + struct samsung_clk_pll *clk_pll;
>> + struct clk *clk;
>> + struct clk_init_data init;
>> + int ret;
>> +
>> + clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
>> + if (!clk_pll) {
>> + pr_err("%s: could not allocate pll clk %s\n", __func__, name);
>> + return;
>> + }
>> +
>> + init.name = name;
>> + init.ops =&samsung_clk_pll_ops;
>> + init.flags = CLK_GET_RATE_NOCACHE;
>> + init.parent_names = pnames;
>> + init.num_parents = 1;
>> +
>> + clk_pll->set_rate = set_rate;
>> + clk_pll->get_rate = get_rate;
>> + clk_pll->hw.init =&init;
>> +
>> + /* register the clock */
>> + clk = clk_register(NULL,&clk_pll->hw);
>> + if (IS_ERR(clk)) {
>> + pr_err("%s: failed to register pll clock %s\n", __func__,
>> + name);
>> + kfree(clk_pll);
>> + return;
>> + }
>> +
>> + ret = clk_register_clkdev(clk, name, NULL);
>> + if (ret)
>> + pr_err("%s: failed to register clock lookup for %s", __func__,
>> + name);
>> +}
>> +
>> +/* register a list of fixed clocks */
>> +void __init samsung_clk_register_fixed_rate(
>> + struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk)
>> +{
>> + struct clk *clk;
>> + unsigned int idx, ret;
>> +
>> + for (idx = 0; idx< nr_clk; idx++, clk_list++) {
>> + clk = clk_register_fixed_rate(NULL, clk_list->name,
>> + clk_list->parent_name, clk_list->flags,
>> + clk_list->fixed_rate);
>> + if (IS_ERR_OR_NULL(clk)) {
>
> clk_register_fixed_rate() always returns an error code (ERR_PTR()), i.e. never
> NULL, thus IS_ERR(clk) is more appropriate here.
Ok. I will change it.
>
>> + pr_err("clock: failed to register clock %s\n",
>> + clk_list->name);
>> + continue;
>> + }
>> +
>> + ret = clk_register_clkdev(clk, clk_list->name,
>> + clk_list->dev_name);
>> + if (ret)
>> + pr_err("clock: failed to register clock lookup for %s",
>> + clk_list->name);
>> + }
>> +}
>> +
>> +/* register a list of mux clocks */
>> +void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
>> + unsigned int nr_clk)
>> +{
>> + struct clk *clk;
>> + unsigned int idx, ret;
>> +
>> + for (idx = 0; idx< nr_clk; idx++, clk_list++) {
>> + clk = clk_register_mux(NULL, clk_list->name,
>> + clk_list->parent_names, clk_list->num_parents,
>> + clk_list->flags, clk_list->reg, clk_list->shift,
>> + clk_list->width, clk_list->mux_flags,&lock);
>> + if (IS_ERR_OR_NULL(clk)) {
>
> Ditto.
>
>> + pr_err("clock: failed to register clock %s\n",
>> + clk_list->name);
>> + continue;
>> + }
>> +
>> + ret = clk_register_clkdev(clk, clk_list->name,
>> + clk_list->dev_name);
>> + if (ret)
>> + pr_err("clock: failed to register clock lookup for %s",
>> + clk_list->name);
>> +
>> + if (clk_list->alias)
>> + clk_register_clkdev(clk, clk_list->alias,
>> + clk_list->dev_name);
>> + }
>> +}
>> +
>> +/* reguster a list of div clocks */
>> +void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
>> + unsigned int nr_clk)
>> +{
>> + struct clk *clk;
>> + unsigned int idx, ret;
>> +
>> + for (idx = 0; idx< nr_clk; idx++, clk_list++) {
>> + clk = clk_register_divider(NULL, clk_list->name,
>> + clk_list->parent_name, clk_list->flags, clk_list->reg,
>> + clk_list->shift, clk_list->width, clk_list->div_flags,
>> + &lock);
>> + if (IS_ERR_OR_NULL(clk)) {
>
> Ditto.
>
>> + pr_err("clock: failed to register clock %s\n",
>> + clk_list->name);
>> + continue;
>> + }
>> +
>> + ret = clk_register_clkdev(clk, clk_list->name,
>> + clk_list->dev_name);
>> + if (ret)
>> + pr_err("clock: failed to register clock lookup for %s",
>> + clk_list->name);
>> +
>> + if (clk_list->alias)
>> + clk_register_clkdev(clk, clk_list->alias,
>> + clk_list->dev_name);
>> + }
>> +}
>> +
>> +/* register a list of gate clocks */
>> +void __init samsung_clk_register_gate(struct samsung_gate_clock *clk_list,
>> + unsigned int nr_clk)
>> +{
>> + struct clk *clk;
>> + unsigned int idx, ret;
>> +
>> + for (idx = 0; idx< nr_clk; idx++, clk_list++) {
>> + clk = clk_register_gate(NULL, clk_list->name,
>> + clk_list->parent_name, clk_list->flags, clk_list->reg,
>> + clk_list->bit_idx, clk_list->gate_flags,&lock);
>> + if (IS_ERR_OR_NULL(clk)) {
>
> Ditto.
>
>> + pr_err("clock: failed to register clock %s\n",
>> + clk_list->name);
>> + continue;
>> + }
>> +
>> + ret = clk_register_clkdev(clk, clk_list->name,
>> + clk_list->dev_name);
>> + if (ret) {
>> + pr_err("clock: failed to register clock lookup for %s",
>> + clk_list->name);
>> + continue;
>> + }
>> +
>> + ret = clk_register_clkdev(clk, clk_list->alias,
>> + clk_list->dev_name);
>> + if (ret)
>> + pr_err("clock: failed to register alias %s for clock "
>> + " %s", clk_list->alias, clk_list->name);
>> + }
>> +}
>
>
> Do we really need all these clock lookup entries registered for each clk
> primitive ? There seem to be more struck clk objects than with the original
> samsung clock code, now when each instance of struct clk_clksrc has been
> replaced with a corresponding div and mux clock object. All these are not
> needed to be referenced from drivers, so why do we see so many
> clk_register_clkdev() here ?
>
> Couldn't this be avoided by instantiating all platform clocks first and
> then creating required clock object - device associations by adding the
> clkdev lookup entries ? Something like this is done in case of
> arch/arm/mach-imx for instance. I think this would result in less data
> and more clear implementation.
Ok. But the platform code can lookup these clocks (for displaying the
clock speed on the console) and hence all the clocks are registered.
Anyway, these are required only for non-dt platforms and would go away
after switching over to device tree based clock registration.
Thanks,
Thomas.
>
>
>> +/* utility function to get the rate of a specified clock */
>> +unsigned long _get_rate(const char *clk_name)
>> +{
>> + struct clk *clk;
>> + unsigned long rate;
>> +
>> + clk = clk_get(NULL, clk_name);
>> + if (IS_ERR(clk))
>> + return 0;
>> + rate = clk_get_rate(clk);
>> + clk_put(clk);
>> + return rate;
>> +}
>> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
>> new file mode 100644
>> index 0000000..40bdff9
>> --- /dev/null
>> +++ b/drivers/clk/samsung/clk.h
>> @@ -0,0 +1,190 @@
>> +/*
>> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>> + * Copyright (c) 2012 Linaro Ltd.
>> + *
>> + * 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.
>> + *
>> + * Common Clock Framework support for all Samsung platforms
>> +*/
>> +
>> +#ifndef __SAMSUNG_CLK_H
>> +#define __SAMSUNG_CLK_H
>> +
>> +#include<linux/clk.h>
>> +#include<linux/clkdev.h>
>> +#include<linux/io.h>
>> +#include<linux/clk-provider.h>
>> +#include<mach/regs-clock.h>
>> +
>> +/**
>> + * struct samsung_clk_pll: represents a samsung pll type clock
>> + * @hw: connection to struct clk.
>> + * @set_rate: callback for setting the pll clock rate
>> + * @get_rate: callback for determing the pll clock rate
>> + *
>> + * Internal representation of the pll type clock. Platform specific
>> + * implementation can instantiate clocks of this type by calling
>> + * samsung_clk_register_pll() function.
>> + */
>> +struct samsung_clk_pll {
>> + struct clk_hw hw;
>> + int (*set_rate)(unsigned long rate);
>> + unsigned long (*get_rate)(unsigned long xtal_rate);
>> +};
>> +
>> +/**
>> + * struct samsung_fixed_rate_clock: information about fixed-rate clock
>> + * @dev_name: name of the device to which this clock belongs.
>> + * @name: name of this fixed-rate clock.
>> + * @parent_name: optional parent clock name.
>> + * @flags: optional fixed-rate clock flags.
>> + * @fixed-rate: fixed clock rate of this clock.
>> + */
>> +struct samsung_fixed_rate_clock {
>> + const char *dev_name;
>> + const char *name;
>> + const char *parent_name;
>> + unsigned long flags;
>> + unsigned long fixed_rate;
>> +};
>> +
>> +#define FRATE_CLK(dname, cname, pname, f, frate) \
>> + { \
>> + .dev_name = dname, \
>> + .name = cname, \
>> + .parent_name = pname, \
>> + .flags = f, \
>> + .fixed_rate = frate, \
>> + }
>> +
>> +/**
>> + * struct samsung_mux_clock: information about mux clock
>> + * @dev_name: name of the device to which this clock belongs.
>> + * @name: name of this mux clock.
>> + * @parent_names: array of pointer to parent clock names.
>> + * @num_parents: number of parents listed in @parent_names.
>> + * @flags: optional flags for basic clock.
>> + * @reg: address of register for configuring the mux.
>> + * @shift: starting bit location of the mux control bit-field in @reg.
>> + * @width: width of the mux control bit-field in @reg.
>> + * @mux_flags: flags for mux-type clock.
>> + * @alias: optional clock alias name to be assigned to this clock.
>> + */
>> +struct samsung_mux_clock {
>> + const char *dev_name;
>> + const char *name;
>> + const char **parent_names;
>> + u8 num_parents;
>> + unsigned long flags;
>> + void __iomem *reg;
>> + u8 shift;
>> + u8 width;
>> + u8 mux_flags;
>> + const char *alias;
>> +};
>> +
>> +#define MUXCLK(dname, cname, pnames, f, r, s, w, mf) \
>> + { \
>> + .dev_name = dname, \
>> + .name = cname, \
>> + .parent_names = pnames, \
>> + .num_parents = ARRAY_SIZE(pnames), \
>> + .flags = f, \
>> + .reg = r, \
>> + .shift = s, \
>> + .width = w, \
>> + .mux_flags = mf, \
>> + }
>> +
>> +/**
>> + * struct samsung_div_clock: information about div clock
>> + * @dev_name: name of the device to which this clock belongs.
>> + * @name: name of this div clock.
>> + * @parent_name: name of the parent clock.
>> + * @flags: optional flags for basic clock.
>> + * @reg: address of register for configuring the div.
>> + * @shift: starting bit location of the div control bit-field in @reg.
>> + * @div_flags: flags for div-type clock.
>> + * @alias: optional clock alias name to be assigned to this clock.
>> + */
>> +struct samsung_div_clock {
>> + const char *dev_name;
>> + const char *name;
>> + const char *parent_name;
>> + unsigned long flags;
>> + void __iomem *reg;
>> + u8 shift;
>> + u8 width;
>> + u8 div_flags;
>> + const char *alias;
>> +};
>> +
>> +#define DIVCLK(dname, cname, pname, f, r, s, w, df) \
>> + { \
>> + .dev_name = dname, \
>> + .name = cname, \
>> + .parent_name = pname, \
>> + .flags = f, \
>> + .reg = r, \
>> + .shift = s, \
>> + .width = w, \
>> + .div_flags = df, \
>> + }
>> +
>> +/**
>> + * struct samsung_gate_clock: information about gate clock
>> + * @dev_name: name of the device to which this clock belongs.
>> + * @name: name of this gate clock.
>> + * @parent_name: name of the parent clock.
>> + * @flags: optional flags for basic clock.
>> + * @reg: address of register for configuring the gate.
>> + * @bit_idx: bit index of the gate control bit-field in @reg.
>> + * @gate_flags: flags for gate-type clock.
>> + * @alias: optional clock alias name to be assigned to this clock.
>> + */
>> +struct samsung_gate_clock {
>> + const char *dev_name;
>> + const char *name;
>> + const char *parent_name;
>> + unsigned long flags;
>> + void __iomem *reg;
>> + u8 bit_idx;
>> + u8 gate_flags;
>> + const char *alias;
>> +};
>> +
>> +#define GATECLK(dname, cname, pname, f, r, b, a) \
>> + { \
>> + .dev_name = dname, \
>> + .name = cname, \
>> + .parent_name = pname, \
>> + .flags = f, \
>> + .reg = r, \
>> + .bit_idx = b, \
>> + .alias = a, \
>> + }
>
> --
>
> Regards,
> Sylwester
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox