2015-02-06 03:27:51 +03:00
/*
* AMD ACPI support for ACPI2platform device .
*
* Copyright ( c ) 2014 , 2015 AMD Corporation .
* Authors : Ken Xue < Ken . Xue @ amd . com >
* Wu , Jeff < Jeff . Wu @ amd . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/clk-provider.h>
# include <linux/platform_device.h>
# include <linux/pm_domain.h>
# include <linux/clkdev.h>
# include <linux/acpi.h>
# include <linux/err.h>
# include <linux/pm.h>
# include "internal.h"
ACPI_MODULE_NAME ( " acpi_apd " ) ;
struct apd_private_data ;
/**
* ACPI_APD_SYSFS : add device attributes in sysfs
* ACPI_APD_PM : attach power domain to device
*/
# define ACPI_APD_SYSFS BIT(0)
# define ACPI_APD_PM BIT(1)
/**
* struct apd_device_desc - a descriptor for apd device
* @ flags : device flags like % ACPI_APD_SYSFS , % ACPI_APD_PM
* @ fixed_clk_rate : fixed rate input clock source for acpi device ;
* 0 means no fixed rate input clock source
* @ setup : a hook routine to set device resource during create platform device
*
* Device description defined as acpi_device_id . driver_data
*/
struct apd_device_desc {
unsigned int flags ;
unsigned int fixed_clk_rate ;
2016-08-23 11:33:26 +03:00
struct property_entry * properties ;
2015-02-06 03:27:51 +03:00
int ( * setup ) ( struct apd_private_data * pdata ) ;
} ;
struct apd_private_data {
struct clk * clk ;
struct acpi_device * adev ;
const struct apd_device_desc * dev_desc ;
} ;
2015-12-11 00:19:16 +03:00
# if defined(CONFIG_X86_AMD_PLATFORM_DEVICE) || defined(CONFIG_ARM64)
2015-02-06 03:27:51 +03:00
# define APD_ADDR(desc) ((unsigned long)&desc)
static int acpi_apd_setup ( struct apd_private_data * pdata )
{
const struct apd_device_desc * dev_desc = pdata - > dev_desc ;
struct clk * clk = ERR_PTR ( - ENODEV ) ;
if ( dev_desc - > fixed_clk_rate ) {
clk = clk_register_fixed_rate ( & pdata - > adev - > dev ,
dev_name ( & pdata - > adev - > dev ) ,
2016-04-20 04:27:46 +03:00
NULL , 0 , dev_desc - > fixed_clk_rate ) ;
2015-02-06 03:27:51 +03:00
clk_register_clkdev ( clk , NULL , dev_name ( & pdata - > adev - > dev ) ) ;
pdata - > clk = clk ;
}
return 0 ;
}
2015-12-11 00:19:16 +03:00
# ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
2016-09-11 16:06:06 +03:00
static const struct apd_device_desc cz_i2c_desc = {
2015-02-06 03:27:51 +03:00
. setup = acpi_apd_setup ,
. fixed_clk_rate = 133000000 ,
} ;
2016-08-23 11:33:26 +03:00
static struct property_entry uart_properties [ ] = {
PROPERTY_ENTRY_U32 ( " reg-io-width " , 4 ) ,
PROPERTY_ENTRY_U32 ( " reg-shift " , 2 ) ,
PROPERTY_ENTRY_BOOL ( " snps,uart-16550-compatible " ) ,
{ } ,
} ;
2016-09-11 16:06:06 +03:00
static const struct apd_device_desc cz_uart_desc = {
2015-02-06 03:27:51 +03:00
. setup = acpi_apd_setup ,
. fixed_clk_rate = 48000000 ,
2016-08-23 11:33:26 +03:00
. properties = uart_properties ,
2015-02-06 03:27:51 +03:00
} ;
2015-12-11 00:19:16 +03:00
# endif
# ifdef CONFIG_ARM64
2016-09-11 16:06:06 +03:00
static const struct apd_device_desc xgene_i2c_desc = {
2015-12-11 00:19:16 +03:00
. setup = acpi_apd_setup ,
. fixed_clk_rate = 100000000 ,
} ;
2016-08-09 17:05:21 +03:00
2016-09-11 16:06:06 +03:00
static const struct apd_device_desc vulcan_spi_desc = {
2016-08-09 17:05:21 +03:00
. setup = acpi_apd_setup ,
. fixed_clk_rate = 133000000 ,
} ;
2015-12-11 00:19:16 +03:00
# endif
2015-02-06 03:27:51 +03:00
# else
# define APD_ADDR(desc) (0UL)
# endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */
/**
* Create platform device during acpi scan attach handle .
* Return value > 0 on success of creating device .
*/
static int acpi_apd_create_device ( struct acpi_device * adev ,
const struct acpi_device_id * id )
{
const struct apd_device_desc * dev_desc = ( void * ) id - > driver_data ;
struct apd_private_data * pdata ;
struct platform_device * pdev ;
int ret ;
if ( ! dev_desc ) {
pdev = acpi_create_platform_device ( adev ) ;
return IS_ERR_OR_NULL ( pdev ) ? PTR_ERR ( pdev ) : 1 ;
}
pdata = kzalloc ( sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return - ENOMEM ;
pdata - > adev = adev ;
pdata - > dev_desc = dev_desc ;
if ( dev_desc - > setup ) {
ret = dev_desc - > setup ( pdata ) ;
if ( ret )
goto err_out ;
}
2016-08-23 11:33:26 +03:00
if ( dev_desc - > properties ) {
ret = device_add_properties ( & adev - > dev , dev_desc - > properties ) ;
if ( ret )
goto err_out ;
}
2015-02-06 03:27:51 +03:00
adev - > driver_data = pdata ;
pdev = acpi_create_platform_device ( adev ) ;
if ( ! IS_ERR_OR_NULL ( pdev ) )
return 1 ;
ret = PTR_ERR ( pdev ) ;
adev - > driver_data = NULL ;
err_out :
kfree ( pdata ) ;
return ret ;
}
static const struct acpi_device_id acpi_apd_device_ids [ ] = {
/* Generic apd devices */
2015-12-11 00:19:16 +03:00
# ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
2015-02-06 03:27:51 +03:00
{ " AMD0010 " , APD_ADDR ( cz_i2c_desc ) } ,
2016-03-10 14:34:52 +03:00
{ " AMDI0010 " , APD_ADDR ( cz_i2c_desc ) } ,
2015-02-06 03:27:51 +03:00
{ " AMD0020 " , APD_ADDR ( cz_uart_desc ) } ,
2016-03-11 12:28:23 +03:00
{ " AMDI0020 " , APD_ADDR ( cz_uart_desc ) } ,
2015-02-06 03:27:51 +03:00
{ " AMD0030 " , } ,
2015-12-11 00:19:16 +03:00
# endif
# ifdef CONFIG_ARM64
{ " APMC0D0F " , APD_ADDR ( xgene_i2c_desc ) } ,
2016-08-09 17:05:21 +03:00
{ " BRCM900D " , APD_ADDR ( vulcan_spi_desc ) } ,
2015-12-11 00:19:16 +03:00
# endif
2015-02-06 03:27:51 +03:00
{ }
} ;
static struct acpi_scan_handler apd_handler = {
. ids = acpi_apd_device_ids ,
. attach = acpi_apd_create_device ,
} ;
void __init acpi_apd_init ( void )
{
acpi_scan_add_handler ( & apd_handler ) ;
}