aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeikki Krogerus <heikki.krogerus@linux.intel.com>2014-05-19 07:42:07 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-25 08:40:57 -0400
commited3a872e2ef62bde06e2f579d8d1458766ced078 (patch)
treee9fbe9e2f6bb3bbb2b0cb336f8f16d2f5404292a
parent5a3c7c09e015c1ba23e6e4951daeccfcfa4189ca (diff)
ACPI / LPSS: support for fractional divider clock
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>
-rw-r--r--drivers/acpi/acpi_lpss.c75
1 files changed, 52 insertions, 23 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index a01d4d1343dd..d1c9b04e29a3 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -29,6 +29,7 @@ ACPI_MODULE_NAME("acpi_lpss");
29#define LPSS_LTR_SIZE 0x18 29#define LPSS_LTR_SIZE 0x18
30 30
31/* Offsets relative to LPSS_PRIVATE_OFFSET */ 31/* Offsets relative to LPSS_PRIVATE_OFFSET */
32#define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16))
32#define LPSS_GENERAL 0x08 33#define LPSS_GENERAL 0x08
33#define LPSS_GENERAL_LTR_MODE_SW BIT(2) 34#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
34#define LPSS_GENERAL_UART_RTS_OVRD BIT(3) 35#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
@@ -60,6 +61,7 @@ struct lpss_device_desc {
60 bool ltr_required; 61 bool ltr_required;
61 unsigned int prv_offset; 62 unsigned int prv_offset;
62 size_t prv_size_override; 63 size_t prv_size_override;
64 bool clk_divider;
63 bool clk_gate; 65 bool clk_gate;
64 bool save_ctx; 66 bool save_ctx;
65 struct lpss_shared_clock *shared_clock; 67 struct lpss_shared_clock *shared_clock;
@@ -97,6 +99,14 @@ static struct lpss_device_desc lpt_dev_desc = {
97 .clk_required = true, 99 .clk_required = true,
98 .prv_offset = 0x800, 100 .prv_offset = 0x800,
99 .ltr_required = true, 101 .ltr_required = true,
102 .clk_divider = true,
103 .clk_gate = true,
104};
105
106static struct lpss_device_desc lpt_i2c_dev_desc = {
107 .clk_required = true,
108 .prv_offset = 0x800,
109 .ltr_required = true,
100 .clk_gate = true, 110 .clk_gate = true,
101}; 111};
102 112
@@ -104,6 +114,7 @@ static struct lpss_device_desc lpt_uart_dev_desc = {
104 .clk_required = true, 114 .clk_required = true,
105 .prv_offset = 0x800, 115 .prv_offset = 0x800,
106 .ltr_required = true, 116 .ltr_required = true,
117 .clk_divider = true,
107 .clk_gate = true, 118 .clk_gate = true,
108 .setup = lpss_uart_setup, 119 .setup = lpss_uart_setup,
109}; 120};
@@ -125,31 +136,21 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
125 .shared_clock = &pwm_clock, 136 .shared_clock = &pwm_clock,
126}; 137};
127 138
128static struct lpss_shared_clock uart_clock = {
129 .name = "uart_clk",
130 .rate = 44236800,
131};
132
133static struct lpss_device_desc byt_uart_dev_desc = { 139static struct lpss_device_desc byt_uart_dev_desc = {
134 .clk_required = true, 140 .clk_required = true,
135 .prv_offset = 0x800, 141 .prv_offset = 0x800,
142 .clk_divider = true,
136 .clk_gate = true, 143 .clk_gate = true,
137 .save_ctx = true, 144 .save_ctx = true,
138 .shared_clock = &uart_clock,
139 .setup = lpss_uart_setup, 145 .setup = lpss_uart_setup,
140}; 146};
141 147
142static struct lpss_shared_clock spi_clock = {
143 .name = "spi_clk",
144 .rate = 50000000,
145};
146
147static struct lpss_device_desc byt_spi_dev_desc = { 148static struct lpss_device_desc byt_spi_dev_desc = {
148 .clk_required = true, 149 .clk_required = true,
149 .prv_offset = 0x400, 150 .prv_offset = 0x400,
151 .clk_divider = true,
150 .clk_gate = true, 152 .clk_gate = true,
151 .save_ctx = true, 153 .save_ctx = true,
152 .shared_clock = &spi_clock,
153}; 154};
154 155
155static struct lpss_device_desc byt_sdio_dev_desc = { 156static struct lpss_device_desc byt_sdio_dev_desc = {
@@ -175,8 +176,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
175 /* Lynxpoint LPSS devices */ 176 /* Lynxpoint LPSS devices */
176 { "INT33C0", (unsigned long)&lpt_dev_desc }, 177 { "INT33C0", (unsigned long)&lpt_dev_desc },
177 { "INT33C1", (unsigned long)&lpt_dev_desc }, 178 { "INT33C1", (unsigned long)&lpt_dev_desc },
178 { "INT33C2", (unsigned long)&lpt_dev_desc }, 179 { "INT33C2", (unsigned long)&lpt_i2c_dev_desc },
179 { "INT33C3", (unsigned long)&lpt_dev_desc }, 180 { "INT33C3", (unsigned long)&lpt_i2c_dev_desc },
180 { "INT33C4", (unsigned long)&lpt_uart_dev_desc }, 181 { "INT33C4", (unsigned long)&lpt_uart_dev_desc },
181 { "INT33C5", (unsigned long)&lpt_uart_dev_desc }, 182 { "INT33C5", (unsigned long)&lpt_uart_dev_desc },
182 { "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, 183 { "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
@@ -192,8 +193,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
192 193
193 { "INT3430", (unsigned long)&lpt_dev_desc }, 194 { "INT3430", (unsigned long)&lpt_dev_desc },
194 { "INT3431", (unsigned long)&lpt_dev_desc }, 195 { "INT3431", (unsigned long)&lpt_dev_desc },
195 { "INT3432", (unsigned long)&lpt_dev_desc }, 196 { "INT3432", (unsigned long)&lpt_i2c_dev_desc },
196 { "INT3433", (unsigned long)&lpt_dev_desc }, 197 { "INT3433", (unsigned long)&lpt_i2c_dev_desc },
197 { "INT3434", (unsigned long)&lpt_uart_dev_desc }, 198 { "INT3434", (unsigned long)&lpt_uart_dev_desc },
198 { "INT3435", (unsigned long)&lpt_uart_dev_desc }, 199 { "INT3435", (unsigned long)&lpt_uart_dev_desc },
199 { "INT3436", (unsigned long)&lpt_sdio_dev_desc }, 200 { "INT3436", (unsigned long)&lpt_sdio_dev_desc },
@@ -221,9 +222,11 @@ static int register_device_clock(struct acpi_device *adev,
221{ 222{
222 const struct lpss_device_desc *dev_desc = pdata->dev_desc; 223 const struct lpss_device_desc *dev_desc = pdata->dev_desc;
223 struct lpss_shared_clock *shared_clock = dev_desc->shared_clock; 224 struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
225 const char *devname = dev_name(&adev->dev);
224 struct clk *clk = ERR_PTR(-ENODEV); 226 struct clk *clk = ERR_PTR(-ENODEV);
225 struct lpss_clk_data *clk_data; 227 struct lpss_clk_data *clk_data;
226 const char *parent; 228 const char *parent, *clk_name;
229 void __iomem *prv_base;
227 230
228 if (!lpss_clk_dev) 231 if (!lpss_clk_dev)
229 lpt_register_clock_device(); 232 lpt_register_clock_device();
@@ -234,7 +237,7 @@ static int register_device_clock(struct acpi_device *adev,
234 237
235 if (dev_desc->clkdev_name) { 238 if (dev_desc->clkdev_name) {
236 clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, 239 clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
237 dev_name(&adev->dev)); 240 devname);
238 return 0; 241 return 0;
239 } 242 }
240 243
@@ -243,6 +246,7 @@ static int register_device_clock(struct acpi_device *adev,
243 return -ENODATA; 246 return -ENODATA;
244 247
245 parent = clk_data->name; 248 parent = clk_data->name;
249 prv_base = pdata->mmio_base + dev_desc->prv_offset;
246 250
247 if (shared_clock) { 251 if (shared_clock) {
248 clk = shared_clock->clk; 252 clk = shared_clock->clk;
@@ -256,16 +260,41 @@ static int register_device_clock(struct acpi_device *adev,
256 } 260 }
257 261
258 if (dev_desc->clk_gate) { 262 if (dev_desc->clk_gate) {
259 clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0, 263 clk = clk_register_gate(NULL, devname, parent, 0,
260 pdata->mmio_base + dev_desc->prv_offset, 264 prv_base, 0, 0, NULL);
261 0, 0, NULL); 265 parent = devname;
262 pdata->clk = clk; 266 }
267
268 if (dev_desc->clk_divider) {
269 /* Prevent division by zero */
270 if (!readl(prv_base))
271 writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base);
272
273 clk_name = kasprintf(GFP_KERNEL, "%s-div", devname);
274 if (!clk_name)
275 return -ENOMEM;
276 clk = clk_register_fractional_divider(NULL, clk_name, parent,
277 0, prv_base,
278 1, 15, 16, 15, 0, NULL);
279 parent = clk_name;
280
281 clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
282 if (!clk_name) {
283 kfree(parent);
284 return -ENOMEM;
285 }
286 clk = clk_register_gate(NULL, clk_name, parent,
287 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
288 prv_base, 31, 0, NULL);
289 kfree(parent);
290 kfree(clk_name);
263 } 291 }
264 292
265 if (IS_ERR(clk)) 293 if (IS_ERR(clk))
266 return PTR_ERR(clk); 294 return PTR_ERR(clk);
267 295
268 clk_register_clkdev(clk, NULL, dev_name(&adev->dev)); 296 pdata->clk = clk;
297 clk_register_clkdev(clk, NULL, devname);
269 return 0; 298 return 0;
270} 299}
271 300