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