Skip to content

Commit

Permalink
ACPI / LPSS: support for fractional divider clock
Browse files Browse the repository at this point in the history
This creates fractional divider type clock for the ones that
have it. It is needed by the UART driver as the clock rate must
accommodate to the requested baud rate.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Heikki Krogerus authored and Rafael J. Wysocki committed May 25, 2014
1 parent 5a3c7c0 commit ed3a872
Showing 1 changed file with 52 additions and 23 deletions.
75 changes: 52 additions & 23 deletions drivers/acpi/acpi_lpss.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_LTR_SIZE 0x18

/* Offsets relative to LPSS_PRIVATE_OFFSET */
#define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16))
#define LPSS_GENERAL 0x08
#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
Expand Down Expand Up @@ -60,6 +61,7 @@ struct lpss_device_desc {
bool ltr_required;
unsigned int prv_offset;
size_t prv_size_override;
bool clk_divider;
bool clk_gate;
bool save_ctx;
struct lpss_shared_clock *shared_clock;
Expand Down Expand Up @@ -94,6 +96,14 @@ static void lpss_uart_setup(struct lpss_private_data *pdata)
}

static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
.clk_divider = true,
.clk_gate = true,
};

static struct lpss_device_desc lpt_i2c_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
Expand All @@ -104,6 +114,7 @@ static struct lpss_device_desc lpt_uart_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
.clk_divider = true,
.clk_gate = true,
.setup = lpss_uart_setup,
};
Expand All @@ -125,31 +136,21 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
.shared_clock = &pwm_clock,
};

static struct lpss_shared_clock uart_clock = {
.name = "uart_clk",
.rate = 44236800,
};

static struct lpss_device_desc byt_uart_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.clk_divider = true,
.clk_gate = true,
.save_ctx = true,
.shared_clock = &uart_clock,
.setup = lpss_uart_setup,
};

static struct lpss_shared_clock spi_clock = {
.name = "spi_clk",
.rate = 50000000,
};

static struct lpss_device_desc byt_spi_dev_desc = {
.clk_required = true,
.prv_offset = 0x400,
.clk_divider = true,
.clk_gate = true,
.save_ctx = true,
.shared_clock = &spi_clock,
};

static struct lpss_device_desc byt_sdio_dev_desc = {
Expand All @@ -175,8 +176,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
/* Lynxpoint LPSS devices */
{ "INT33C0", (unsigned long)&lpt_dev_desc },
{ "INT33C1", (unsigned long)&lpt_dev_desc },
{ "INT33C2", (unsigned long)&lpt_dev_desc },
{ "INT33C3", (unsigned long)&lpt_dev_desc },
{ "INT33C2", (unsigned long)&lpt_i2c_dev_desc },
{ "INT33C3", (unsigned long)&lpt_i2c_dev_desc },
{ "INT33C4", (unsigned long)&lpt_uart_dev_desc },
{ "INT33C5", (unsigned long)&lpt_uart_dev_desc },
{ "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
Expand All @@ -192,8 +193,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {

{ "INT3430", (unsigned long)&lpt_dev_desc },
{ "INT3431", (unsigned long)&lpt_dev_desc },
{ "INT3432", (unsigned long)&lpt_dev_desc },
{ "INT3433", (unsigned long)&lpt_dev_desc },
{ "INT3432", (unsigned long)&lpt_i2c_dev_desc },
{ "INT3433", (unsigned long)&lpt_i2c_dev_desc },
{ "INT3434", (unsigned long)&lpt_uart_dev_desc },
{ "INT3435", (unsigned long)&lpt_uart_dev_desc },
{ "INT3436", (unsigned long)&lpt_sdio_dev_desc },
Expand Down Expand Up @@ -221,9 +222,11 @@ static int register_device_clock(struct acpi_device *adev,
{
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);
struct clk *clk = ERR_PTR(-ENODEV);
struct lpss_clk_data *clk_data;
const char *parent;
const char *parent, *clk_name;
void __iomem *prv_base;

if (!lpss_clk_dev)
lpt_register_clock_device();
Expand All @@ -234,7 +237,7 @@ static int register_device_clock(struct acpi_device *adev,

if (dev_desc->clkdev_name) {
clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
dev_name(&adev->dev));
devname);
return 0;
}

Expand All @@ -243,6 +246,7 @@ static int register_device_clock(struct acpi_device *adev,
return -ENODATA;

parent = clk_data->name;
prv_base = pdata->mmio_base + dev_desc->prv_offset;

if (shared_clock) {
clk = shared_clock->clk;
Expand All @@ -256,16 +260,41 @@ static int register_device_clock(struct acpi_device *adev,
}

if (dev_desc->clk_gate) {
clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0,
pdata->mmio_base + dev_desc->prv_offset,
0, 0, NULL);
pdata->clk = clk;
clk = clk_register_gate(NULL, devname, parent, 0,
prv_base, 0, 0, NULL);
parent = devname;
}

if (dev_desc->clk_divider) {
/* Prevent division by zero */
if (!readl(prv_base))
writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base);

clk_name = kasprintf(GFP_KERNEL, "%s-div", devname);
if (!clk_name)
return -ENOMEM;
clk = clk_register_fractional_divider(NULL, clk_name, parent,
0, prv_base,
1, 15, 16, 15, 0, NULL);
parent = clk_name;

clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
if (!clk_name) {
kfree(parent);
return -ENOMEM;
}
clk = clk_register_gate(NULL, clk_name, parent,
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
prv_base, 31, 0, NULL);
kfree(parent);
kfree(clk_name);
}

if (IS_ERR(clk))
return PTR_ERR(clk);

clk_register_clkdev(clk, NULL, dev_name(&adev->dev));
pdata->clk = clk;
clk_register_clkdev(clk, NULL, devname);
return 0;
}

Expand Down

0 comments on commit ed3a872

Please sign in to comment.