Merge back earlier 'acpi-lpss' material for v3.18.

This commit is contained in:
Rafael J. Wysocki 2014-09-29 15:29:18 +02:00
commit 3f9ae3790e

View file

@ -54,55 +54,58 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_PRV_REG_COUNT 9 #define LPSS_PRV_REG_COUNT 9
struct lpss_shared_clock { /* LPSS Flags */
const char *name; #define LPSS_CLK BIT(0)
unsigned long rate; #define LPSS_CLK_GATE BIT(1)
struct clk *clk; #define LPSS_CLK_DIVIDER BIT(2)
}; #define LPSS_LTR BIT(3)
#define LPSS_SAVE_CTX BIT(4)
struct lpss_private_data; struct lpss_private_data;
struct lpss_device_desc { struct lpss_device_desc {
bool clk_required; unsigned int flags;
const char *clkdev_name;
bool ltr_required;
unsigned int prv_offset; unsigned int prv_offset;
size_t prv_size_override; size_t prv_size_override;
bool clk_divider;
bool clk_gate;
bool save_ctx;
struct lpss_shared_clock *shared_clock;
void (*setup)(struct lpss_private_data *pdata); void (*setup)(struct lpss_private_data *pdata);
}; };
static struct lpss_device_desc lpss_dma_desc = { static struct lpss_device_desc lpss_dma_desc = {
.clk_required = true, .flags = LPSS_CLK,
.clkdev_name = "hclk",
}; };
struct lpss_private_data { struct lpss_private_data {
void __iomem *mmio_base; void __iomem *mmio_base;
resource_size_t mmio_size; resource_size_t mmio_size;
unsigned int fixed_clk_rate;
struct clk *clk; struct clk *clk;
const struct lpss_device_desc *dev_desc; const struct lpss_device_desc *dev_desc;
u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
}; };
/* UART Component Parameter Register */
#define LPSS_UART_CPR 0xF4
#define LPSS_UART_CPR_AFCE BIT(4)
static void lpss_uart_setup(struct lpss_private_data *pdata) static void lpss_uart_setup(struct lpss_private_data *pdata)
{ {
unsigned int offset; unsigned int offset;
u32 reg; u32 val;
offset = pdata->dev_desc->prv_offset + LPSS_TX_INT; offset = pdata->dev_desc->prv_offset + LPSS_TX_INT;
reg = readl(pdata->mmio_base + offset); val = readl(pdata->mmio_base + offset);
writel(reg | LPSS_TX_INT_MASK, pdata->mmio_base + offset); writel(val | LPSS_TX_INT_MASK, pdata->mmio_base + offset);
val = readl(pdata->mmio_base + LPSS_UART_CPR);
if (!(val & LPSS_UART_CPR_AFCE)) {
offset = pdata->dev_desc->prv_offset + LPSS_GENERAL; offset = pdata->dev_desc->prv_offset + LPSS_GENERAL;
reg = readl(pdata->mmio_base + offset); val = readl(pdata->mmio_base + offset);
writel(reg | LPSS_GENERAL_UART_RTS_OVRD, pdata->mmio_base + offset); val |= LPSS_GENERAL_UART_RTS_OVRD;
writel(val, pdata->mmio_base + offset);
}
} }
static void lpss_i2c_setup(struct lpss_private_data *pdata) static void byt_i2c_setup(struct lpss_private_data *pdata)
{ {
unsigned int offset; unsigned int offset;
u32 val; u32 val;
@ -111,100 +114,56 @@ static void lpss_i2c_setup(struct lpss_private_data *pdata)
val = readl(pdata->mmio_base + offset); val = readl(pdata->mmio_base + offset);
val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC; val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC;
writel(val, pdata->mmio_base + offset); writel(val, pdata->mmio_base + offset);
if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
pdata->fixed_clk_rate = 133000000;
} }
static struct lpss_device_desc wpt_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
.clk_divider = true,
.clk_gate = true,
};
static struct lpss_device_desc lpt_dev_desc = { static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true, .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
.prv_offset = 0x800, .prv_offset = 0x800,
.ltr_required = true,
.clk_divider = true,
.clk_gate = true,
}; };
static struct lpss_device_desc lpt_i2c_dev_desc = { static struct lpss_device_desc lpt_i2c_dev_desc = {
.clk_required = true, .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR,
.prv_offset = 0x800, .prv_offset = 0x800,
.ltr_required = true,
.clk_gate = true,
}; };
static struct lpss_device_desc lpt_uart_dev_desc = { static struct lpss_device_desc lpt_uart_dev_desc = {
.clk_required = true, .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
.prv_offset = 0x800, .prv_offset = 0x800,
.ltr_required = true,
.clk_divider = true,
.clk_gate = true,
.setup = lpss_uart_setup, .setup = lpss_uart_setup,
}; };
static struct lpss_device_desc lpt_sdio_dev_desc = { static struct lpss_device_desc lpt_sdio_dev_desc = {
.flags = LPSS_LTR,
.prv_offset = 0x1000, .prv_offset = 0x1000,
.prv_size_override = 0x1018, .prv_size_override = 0x1018,
.ltr_required = true,
};
static struct lpss_shared_clock pwm_clock = {
.name = "pwm_clk",
.rate = 25000000,
}; };
static struct lpss_device_desc byt_pwm_dev_desc = { static struct lpss_device_desc byt_pwm_dev_desc = {
.clk_required = true, .flags = LPSS_SAVE_CTX,
.save_ctx = true,
.shared_clock = &pwm_clock,
}; };
static struct lpss_device_desc byt_uart_dev_desc = { static struct lpss_device_desc byt_uart_dev_desc = {
.clk_required = true, .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.prv_offset = 0x800, .prv_offset = 0x800,
.clk_divider = true,
.clk_gate = true,
.save_ctx = true,
.setup = lpss_uart_setup, .setup = lpss_uart_setup,
}; };
static struct lpss_device_desc byt_spi_dev_desc = { static struct lpss_device_desc byt_spi_dev_desc = {
.clk_required = true, .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.prv_offset = 0x400, .prv_offset = 0x400,
.clk_divider = true,
.clk_gate = true,
.save_ctx = true,
}; };
static struct lpss_device_desc byt_sdio_dev_desc = { static struct lpss_device_desc byt_sdio_dev_desc = {
.clk_required = true, .flags = LPSS_CLK,
};
static struct lpss_shared_clock i2c_clock = {
.name = "i2c_clk",
.rate = 100000000,
}; };
static struct lpss_device_desc byt_i2c_dev_desc = { static struct lpss_device_desc byt_i2c_dev_desc = {
.clk_required = true, .flags = LPSS_CLK | LPSS_SAVE_CTX,
.prv_offset = 0x800, .prv_offset = 0x800,
.save_ctx = true, .setup = byt_i2c_setup,
.shared_clock = &i2c_clock,
.setup = lpss_i2c_setup,
};
static struct lpss_shared_clock bsw_pwm_clock = {
.name = "pwm_clk",
.rate = 19200000,
};
static struct lpss_device_desc bsw_pwm_dev_desc = {
.clk_required = true,
.save_ctx = true,
.shared_clock = &bsw_pwm_clock,
}; };
#else #else
@ -237,7 +196,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT33FC", }, { "INT33FC", },
/* Braswell LPSS devices */ /* Braswell LPSS devices */
{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) }, { "80862288", LPSS_ADDR(byt_pwm_dev_desc) },
{ "8086228A", LPSS_ADDR(byt_uart_dev_desc) }, { "8086228A", LPSS_ADDR(byt_uart_dev_desc) },
{ "8086228E", LPSS_ADDR(byt_spi_dev_desc) }, { "8086228E", LPSS_ADDR(byt_spi_dev_desc) },
{ "808622C1", LPSS_ADDR(byt_i2c_dev_desc) }, { "808622C1", LPSS_ADDR(byt_i2c_dev_desc) },
@ -251,7 +210,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) }, { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) },
{ "INT3437", }, { "INT3437", },
{ "INT3438", LPSS_ADDR(wpt_dev_desc) }, /* Wildcat Point LPSS devices */
{ "INT3438", LPSS_ADDR(lpt_dev_desc) },
{ } { }
}; };
@ -276,7 +236,6 @@ static int register_device_clock(struct acpi_device *adev,
struct lpss_private_data *pdata) struct lpss_private_data *pdata)
{ {
const struct lpss_device_desc *dev_desc = pdata->dev_desc; const struct lpss_device_desc *dev_desc = pdata->dev_desc;
struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
const char *devname = dev_name(&adev->dev); const char *devname = dev_name(&adev->dev);
struct clk *clk = ERR_PTR(-ENODEV); struct clk *clk = ERR_PTR(-ENODEV);
struct lpss_clk_data *clk_data; struct lpss_clk_data *clk_data;
@ -289,12 +248,7 @@ static int register_device_clock(struct acpi_device *adev,
clk_data = platform_get_drvdata(lpss_clk_dev); clk_data = platform_get_drvdata(lpss_clk_dev);
if (!clk_data) if (!clk_data)
return -ENODEV; return -ENODEV;
clk = clk_data->clk;
if (dev_desc->clkdev_name) {
clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
devname);
return 0;
}
if (!pdata->mmio_base if (!pdata->mmio_base
|| pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE) || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
@ -303,24 +257,19 @@ static int register_device_clock(struct acpi_device *adev,
parent = clk_data->name; parent = clk_data->name;
prv_base = pdata->mmio_base + dev_desc->prv_offset; prv_base = pdata->mmio_base + dev_desc->prv_offset;
if (shared_clock) { if (pdata->fixed_clk_rate) {
clk = shared_clock->clk; clk = clk_register_fixed_rate(NULL, devname, parent, 0,
if (!clk) { pdata->fixed_clk_rate);
clk = clk_register_fixed_rate(NULL, shared_clock->name, goto out;
"lpss_clk", 0,
shared_clock->rate);
shared_clock->clk = clk;
}
parent = shared_clock->name;
} }
if (dev_desc->clk_gate) { if (dev_desc->flags & LPSS_CLK_GATE) {
clk = clk_register_gate(NULL, devname, parent, 0, clk = clk_register_gate(NULL, devname, parent, 0,
prv_base, 0, 0, NULL); prv_base, 0, 0, NULL);
parent = devname; parent = devname;
} }
if (dev_desc->clk_divider) { if (dev_desc->flags & LPSS_CLK_DIVIDER) {
/* Prevent division by zero */ /* Prevent division by zero */
if (!readl(prv_base)) if (!readl(prv_base))
writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base); writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base);
@ -344,7 +293,7 @@ static int register_device_clock(struct acpi_device *adev,
kfree(parent); kfree(parent);
kfree(clk_name); kfree(clk_name);
} }
out:
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
@ -392,7 +341,10 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
pdata->dev_desc = dev_desc; pdata->dev_desc = dev_desc;
if (dev_desc->clk_required) { if (dev_desc->setup)
dev_desc->setup(pdata);
if (dev_desc->flags & LPSS_CLK) {
ret = register_device_clock(adev, pdata); ret = register_device_clock(adev, pdata);
if (ret) { if (ret) {
/* Skip the device, but continue the namespace scan. */ /* Skip the device, but continue the namespace scan. */
@ -413,9 +365,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
goto err_out; goto err_out;
} }
if (dev_desc->setup)
dev_desc->setup(pdata);
adev->driver_data = pdata; adev->driver_data = pdata;
pdev = acpi_create_platform_device(adev); pdev = acpi_create_platform_device(adev);
if (!IS_ERR_OR_NULL(pdev)) { if (!IS_ERR_OR_NULL(pdev)) {
@ -692,19 +641,19 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
switch (action) { switch (action) {
case BUS_NOTIFY_BOUND_DRIVER: case BUS_NOTIFY_BOUND_DRIVER:
if (pdata->dev_desc->save_ctx) if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
pdev->dev.pm_domain = &acpi_lpss_pm_domain; pdev->dev.pm_domain = &acpi_lpss_pm_domain;
break; break;
case BUS_NOTIFY_UNBOUND_DRIVER: case BUS_NOTIFY_UNBOUND_DRIVER:
if (pdata->dev_desc->save_ctx) if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
pdev->dev.pm_domain = NULL; pdev->dev.pm_domain = NULL;
break; break;
case BUS_NOTIFY_ADD_DEVICE: case BUS_NOTIFY_ADD_DEVICE:
if (pdata->dev_desc->ltr_required) if (pdata->dev_desc->flags & LPSS_LTR)
return sysfs_create_group(&pdev->dev.kobj, return sysfs_create_group(&pdev->dev.kobj,
&lpss_attr_group); &lpss_attr_group);
case BUS_NOTIFY_DEL_DEVICE: case BUS_NOTIFY_DEL_DEVICE:
if (pdata->dev_desc->ltr_required) if (pdata->dev_desc->flags & LPSS_LTR)
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
default: default:
break; break;
@ -721,7 +670,7 @@ static void acpi_lpss_bind(struct device *dev)
{ {
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required) if (!pdata || !pdata->mmio_base || !(pdata->dev_desc->flags & LPSS_LTR))
return; return;
if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE)