@@ -1081,3 +1081,4 @@ endif # X86_PLATFORM_DEVICES
config PMC_ATOM
def_bool y
depends on PCI
+ select COMMON_CLK
@@ -19,7 +19,9 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/platform_data/x86/clk-pmc-atom.h>
#include <linux/platform_data/x86/pmc_atom.h>
+#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/seq_file.h>
@@ -36,6 +38,11 @@ struct pmc_reg_map {
const struct pmc_bit_map *pss;
};
+struct pmc_data {
+ const struct pmc_reg_map *map;
+ const struct pmc_clk *clks;
+};
+
struct pmc_dev {
u32 base_addr;
void __iomem *regmap;
@@ -49,6 +56,29 @@ struct pmc_dev {
static struct pmc_dev pmc_device;
static u32 acpi_base_addr;
+static const struct pmc_clk byt_clks[] = {
+ {
+ .name = "xtal",
+ .freq = 25000000,
+ .parent_name = NULL,
+ },
+ {
+ .name = "pll",
+ .freq = 19200000,
+ .parent_name = "xtal",
+ },
+ {},
+};
+
+static const struct pmc_clk cht_clks[] = {
+ {
+ .name = "xtal",
+ .freq = 19200000,
+ .parent_name = NULL,
+ },
+ {},
+};
+
static const struct pmc_bit_map d3_sts_0_map[] = {
{"LPSS1_F0_DMA", BIT_LPSS1_F0_DMA},
{"LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1},
@@ -168,6 +198,16 @@ static const struct pmc_reg_map cht_reg_map = {
.pss = cht_pss_map,
};
+static const struct pmc_data byt_data = {
+ .map = &byt_reg_map,
+ .clks = byt_clks,
+};
+
+static const struct pmc_data cht_data = {
+ .map = &cht_reg_map,
+ .clks = cht_clks,
+};
+
static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset)
{
return readl(pmc->regmap + reg_offset);
@@ -381,10 +421,37 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc)
}
#endif /* CONFIG_DEBUG_FS */
+static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap,
+ const struct pmc_data *pmc_data)
+{
+ struct platform_device *clkdev;
+ struct pmc_clk_data *clk_data;
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->base = pmc_regmap; /* offset is added by client */
+ clk_data->clks = pmc_data->clks;
+
+ clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom",
+ PLATFORM_DEVID_NONE,
+ clk_data, sizeof(*clk_data));
+ if (IS_ERR(clkdev)) {
+ kfree(clk_data);
+ return PTR_ERR(clkdev);
+ }
+
+ kfree(clk_data);
+
+ return 0;
+}
+
static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct pmc_dev *pmc = &pmc_device;
- const struct pmc_reg_map *map = (struct pmc_reg_map *)ent->driver_data;
+ const struct pmc_data *data = (struct pmc_data *)ent->driver_data;
+ const struct pmc_reg_map *map = data->map;
int ret;
/* Obtain ACPI base address */
@@ -413,6 +480,12 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
dev_warn(&pdev->dev, "debugfs register failed\n");
+ /* Register platform clocks - PMC_PLT_CLK [5:0] */
+ ret = pmc_setup_clks(pdev, pmc->regmap, data);
+ if (ret)
+ dev_warn(&pdev->dev, "platform clocks register failed: %d\n",
+ ret);
+
pmc->init = true;
return ret;
}
@@ -423,8 +496,8 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent)
* used by pci_match_id() call below.
*/
static const struct pci_device_id pmc_pci_ids[] = {
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_reg_map },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_reg_map },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data },
{ 0, },
};