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#if defined(CONFIG_X86_AMD_PLATFORM_DEVICE) || defined(CONFIG_ARM64)
  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
  74#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
  75static struct apd_device_desc cz_i2c_desc = {
  76        .setup = acpi_apd_setup,
  77        .fixed_clk_rate = 133000000,
  78};
  79
  80static struct apd_device_desc cz_uart_desc = {
  81        .setup = acpi_apd_setup,
  82        .fixed_clk_rate = 48000000,
  83};
  84#endif
  85
  86#ifdef CONFIG_ARM64
  87static struct apd_device_desc xgene_i2c_desc = {
  88        .setup = acpi_apd_setup,
  89        .fixed_clk_rate = 100000000,
  90};
  91#endif
  92
  93#else
  94
  95#define APD_ADDR(desc) (0UL)
  96
  97#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */
  98
  99/**
 100* Create platform device during acpi scan attach handle.
 101* Return value > 0 on success of creating device.
 102*/
 103static int acpi_apd_create_device(struct acpi_device *adev,
 104                                   const struct acpi_device_id *id)
 105{
 106        const struct apd_device_desc *dev_desc = (void *)id->driver_data;
 107        struct apd_private_data *pdata;
 108        struct platform_device *pdev;
 109        int ret;
 110
 111        if (!dev_desc) {
 112                pdev = acpi_create_platform_device(adev);
 113                return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
 114        }
 115
 116        pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 117        if (!pdata)
 118                return -ENOMEM;
 119
 120        pdata->adev = adev;
 121        pdata->dev_desc = dev_desc;
 122
 123        if (dev_desc->setup) {
 124                ret = dev_desc->setup(pdata);
 125                if (ret)
 126                        goto err_out;
 127        }
 128
 129        adev->driver_data = pdata;
 130        pdev = acpi_create_platform_device(adev);
 131        if (!IS_ERR_OR_NULL(pdev))
 132                return 1;
 133
 134        ret = PTR_ERR(pdev);
 135        adev->driver_data = NULL;
 136
 137 err_out:
 138        kfree(pdata);
 139        return ret;
 140}
 141
 142static const struct acpi_device_id acpi_apd_device_ids[] = {
 143        /* Generic apd devices */
 144#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
 145        { "AMD0010", APD_ADDR(cz_i2c_desc) },
 146        { "AMDI0010", APD_ADDR(cz_i2c_desc) },
 147        { "AMD0020", APD_ADDR(cz_uart_desc) },
 148        { "AMDI0020", APD_ADDR(cz_uart_desc) },
 149        { "AMD0030", },
 150#endif
 151#ifdef CONFIG_ARM64
 152        { "APMC0D0F", APD_ADDR(xgene_i2c_desc) },
 153#endif
 154        { }
 155};
 156
 157static struct acpi_scan_handler apd_handler = {
 158        .ids = acpi_apd_device_ids,
 159        .attach = acpi_apd_create_device,
 160};
 161
 162void __init acpi_apd_init(void)
 163{
 164        acpi_scan_add_handler(&apd_handler);
 165}
 166