linux/drivers/acpi/acpi_apd.c
<<
>>
Prefs
   1/*
   2 * AMD ACPI support for ACPI2platform device.
   3 *
   4 * Copyright (c) 2014,2015 AMD Corporation.
   5 * Authors: Ken Xue <Ken.Xue@amd.com>
   6 *      Wu, Jeff <Jeff.Wu@amd.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/clk-provider.h>
  14#include <linux/platform_device.h>
  15#include <linux/pm_domain.h>
  16#include <linux/clkdev.h>
  17#include <linux/acpi.h>
  18#include <linux/err.h>
  19#include <linux/pm.h>
  20
  21#include "internal.h"
  22
  23ACPI_MODULE_NAME("acpi_apd");
  24struct apd_private_data;
  25
  26/**
  27 * ACPI_APD_SYSFS : add device attributes in sysfs
  28 * ACPI_APD_PM : attach power domain to device
  29 */
  30#define ACPI_APD_SYSFS  BIT(0)
  31#define ACPI_APD_PM     BIT(1)
  32
  33/**
  34 * struct apd_device_desc - a descriptor for apd device
  35 * @flags: device flags like %ACPI_APD_SYSFS, %ACPI_APD_PM
  36 * @fixed_clk_rate: fixed rate input clock source for acpi device;
  37 *                      0 means no fixed rate input clock source
  38 * @setup: a hook routine to set device resource during create platform device
  39 *
  40 * Device description defined as acpi_device_id.driver_data
  41 */
  42struct apd_device_desc {
  43        unsigned int flags;
  44        unsigned int fixed_clk_rate;
  45        int (*setup)(struct apd_private_data *pdata);
  46};
  47
  48struct apd_private_data {
  49        struct clk *clk;
  50        struct acpi_device *adev;
  51        const struct apd_device_desc *dev_desc;
  52};
  53
  54#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
  55#define APD_ADDR(desc)  ((unsigned long)&desc)
  56
  57static int acpi_apd_setup(struct apd_private_data *pdata)
  58{
  59        const struct apd_device_desc *dev_desc = pdata->dev_desc;
  60        struct clk *clk = ERR_PTR(-ENODEV);
  61
  62        if (dev_desc->fixed_clk_rate) {
  63                clk = clk_register_fixed_rate(&pdata->adev->dev,
  64                                        dev_name(&pdata->adev->dev),
  65                                        NULL, CLK_IS_ROOT,
  66                                        dev_desc->fixed_clk_rate);
  67                clk_register_clkdev(clk, NULL, dev_name(&pdata->adev->dev));
  68                pdata->clk = clk;
  69        }
  70
  71        return 0;
  72}
  73
  74static struct apd_device_desc cz_i2c_desc = {
  75        .setup = acpi_apd_setup,
  76        .fixed_clk_rate = 133000000,
  77};
  78
  79static struct apd_device_desc cz_uart_desc = {
  80        .setup = acpi_apd_setup,
  81        .fixed_clk_rate = 48000000,
  82};
  83
  84#else
  85
  86#define APD_ADDR(desc) (0UL)
  87
  88#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */
  89
  90/**
  91* Create platform device during acpi scan attach handle.
  92* Return value > 0 on success of creating device.
  93*/
  94static int acpi_apd_create_device(struct acpi_device *adev,
  95                                   const struct acpi_device_id *id)
  96{
  97        const struct apd_device_desc *dev_desc = (void *)id->driver_data;
  98        struct apd_private_data *pdata;
  99        struct platform_device *pdev;
 100        int ret;
 101
 102        if (!dev_desc) {
 103                pdev = acpi_create_platform_device(adev);
 104                return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
 105        }
 106
 107        pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 108        if (!pdata)
 109                return -ENOMEM;
 110
 111        pdata->adev = adev;
 112        pdata->dev_desc = dev_desc;
 113
 114        if (dev_desc->setup) {
 115                ret = dev_desc->setup(pdata);
 116                if (ret)
 117                        goto err_out;
 118        }
 119
 120        adev->driver_data = pdata;
 121        pdev = acpi_create_platform_device(adev);
 122        if (!IS_ERR_OR_NULL(pdev))
 123                return 1;
 124
 125        ret = PTR_ERR(pdev);
 126        adev->driver_data = NULL;
 127
 128 err_out:
 129        kfree(pdata);
 130        return ret;
 131}
 132
 133static const struct acpi_device_id acpi_apd_device_ids[] = {
 134        /* Generic apd devices */
 135        { "AMD0010", APD_ADDR(cz_i2c_desc) },
 136        { "AMD0020", APD_ADDR(cz_uart_desc) },
 137        { "AMD0030", },
 138        { }
 139};
 140
 141static struct acpi_scan_handler apd_handler = {
 142        .ids = acpi_apd_device_ids,
 143        .attach = acpi_apd_create_device,
 144};
 145
 146void __init acpi_apd_init(void)
 147{
 148        acpi_scan_add_handler(&apd_handler);
 149}
 150