]> Pileus Git - ~andy/linux/blob - drivers/clk/x86/clk-lpss.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[~andy/linux] / drivers / clk / x86 / clk-lpss.c
1 /*
2  * Intel Low Power Subsystem clocks.
3  *
4  * Copyright (C) 2013, Intel Corporation
5  * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
6  *          Heikki Krogerus <heikki.krogerus@linux.intel.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/acpi.h>
14 #include <linux/clk.h>
15 #include <linux/clk-provider.h>
16 #include <linux/err.h>
17 #include <linux/io.h>
18 #include <linux/module.h>
19
20 static int clk_lpss_is_mmio_resource(struct acpi_resource *res, void *data)
21 {
22         struct resource r;
23         return !acpi_dev_resource_memory(res, &r);
24 }
25
26 static acpi_status clk_lpss_find_mmio(acpi_handle handle, u32 level,
27                                       void *data, void **retval)
28 {
29         struct resource_list_entry *rentry;
30         struct list_head resource_list;
31         struct acpi_device *adev;
32         const char *uid = data;
33         int ret;
34
35         if (acpi_bus_get_device(handle, &adev))
36                 return AE_OK;
37
38         if (uid) {
39                 if (!adev->pnp.unique_id)
40                         return AE_OK;
41                 if (strcmp(uid, adev->pnp.unique_id))
42                         return AE_OK;
43         }
44
45         INIT_LIST_HEAD(&resource_list);
46         ret = acpi_dev_get_resources(adev, &resource_list,
47                                      clk_lpss_is_mmio_resource, NULL);
48         if (ret < 0)
49                 return AE_NO_MEMORY;
50
51         list_for_each_entry(rentry, &resource_list, node)
52                 if (resource_type(&rentry->res) == IORESOURCE_MEM) {
53                         *(struct resource *)retval = rentry->res;
54                         break;
55                 }
56
57         acpi_dev_free_resource_list(&resource_list);
58         return AE_OK;
59 }
60
61 /**
62  * clk_register_lpss_gate - register LPSS clock gate
63  * @name: name of this clock gate
64  * @parent_name: parent clock name
65  * @hid: ACPI _HID of the device
66  * @uid: ACPI _UID of the device (optional)
67  * @offset: LPSS PRV_CLOCK_PARAMS offset
68  *
69  * Creates and registers LPSS clock gate.
70  */
71 struct clk *clk_register_lpss_gate(const char *name, const char *parent_name,
72                                    const char *hid, const char *uid,
73                                    unsigned offset)
74 {
75         struct resource res = { };
76         void __iomem *mmio_base;
77         acpi_status status;
78         struct clk *clk;
79
80         /*
81          * First try to look the device and its mmio resource from the
82          * ACPI namespace.
83          */
84         status = acpi_get_devices(hid, clk_lpss_find_mmio, (void *)uid,
85                                   (void **)&res);
86         if (ACPI_FAILURE(status) || !res.start)
87                 return ERR_PTR(-ENODEV);
88
89         mmio_base = ioremap(res.start, resource_size(&res));
90         if (!mmio_base)
91                 return ERR_PTR(-ENOMEM);
92
93         clk = clk_register_gate(NULL, name, parent_name, 0, mmio_base + offset,
94                                 0, 0, NULL);
95         if (IS_ERR(clk))
96                 iounmap(mmio_base);
97
98         return clk;
99 }