2019-01-07 13:07:41 +02:00
// SPDX-License-Identifier: GPL-2.0
2013-06-05 15:26:45 +03:00
/*
* Platform driver for the Synopsys DesignWare DMA Controller
*
* Copyright ( C ) 2007 - 2008 Atmel Corporation
* Copyright ( C ) 2010 - 2011 ST Microelectronics
* Copyright ( C ) 2013 Intel Corporation
*
* Some parts of this driver are derived from the original dw_dmac .
*/
# include <linux/module.h>
# include <linux/device.h>
# include <linux/clk.h>
2015-01-13 18:57:15 +02:00
# include <linux/pm_runtime.h>
2013-06-05 15:26:45 +03:00
# include <linux/platform_device.h>
# include <linux/dmaengine.h>
# include <linux/dma-mapping.h>
# include <linux/of.h>
# include <linux/acpi.h>
# include "internal.h"
2015-03-09 12:16:42 +02:00
# define DRV_NAME "dw_dmac"
2013-06-05 15:26:45 +03:00
static int dw_probe ( struct platform_device * pdev )
{
2019-08-20 16:15:40 +03:00
const struct dw_dma_chip_pdata * match ;
struct dw_dma_chip_pdata * data ;
2013-06-05 15:26:45 +03:00
struct dw_dma_chip * chip ;
struct device * dev = & pdev - > dev ;
int err ;
2019-08-20 16:15:40 +03:00
match = device_get_match_data ( dev ) ;
if ( ! match )
return - ENODEV ;
data = devm_kmemdup ( & pdev - > dev , match , sizeof ( * match ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2013-06-05 15:26:45 +03:00
chip = devm_kzalloc ( dev , sizeof ( * chip ) , GFP_KERNEL ) ;
if ( ! chip )
return - ENOMEM ;
chip - > irq = platform_get_irq ( pdev , 0 ) ;
if ( chip - > irq < 0 )
return chip - > irq ;
2019-08-20 16:15:42 +03:00
chip - > regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
2013-06-05 15:26:45 +03:00
if ( IS_ERR ( chip - > regs ) )
return PTR_ERR ( chip - > regs ) ;
2013-06-27 13:37:21 +01:00
err = dma_coerce_mask_and_coherent ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
if ( err )
return err ;
2013-06-05 15:26:45 +03:00
2019-08-20 16:15:41 +03:00
if ( ! data - > pdata )
data - > pdata = dev_get_platdata ( dev ) ;
if ( ! data - > pdata )
data - > pdata = dw_dma_parse_dt ( pdev ) ;
2013-06-05 15:26:45 +03:00
chip - > dev = dev ;
2017-01-17 13:57:26 +02:00
chip - > id = pdev - > id ;
2019-08-20 16:15:41 +03:00
chip - > pdata = data - > pdata ;
2013-06-05 15:26:45 +03:00
2019-08-20 16:15:40 +03:00
data - > chip = chip ;
2019-09-24 11:51:16 +03:00
chip - > clk = devm_clk_get_optional ( chip - > dev , " hclk " ) ;
2014-08-19 20:29:17 +03:00
if ( IS_ERR ( chip - > clk ) )
return PTR_ERR ( chip - > clk ) ;
err = clk_prepare_enable ( chip - > clk ) ;
2013-06-05 15:26:45 +03:00
if ( err )
return err ;
2015-01-13 18:57:15 +02:00
pm_runtime_enable ( & pdev - > dev ) ;
2019-08-20 16:15:40 +03:00
err = data - > probe ( chip ) ;
2014-08-19 20:29:17 +03:00
if ( err )
goto err_dw_dma_probe ;
2019-08-20 16:15:40 +03:00
platform_set_drvdata ( pdev , data ) ;
2013-06-05 15:26:45 +03:00
2019-08-20 16:15:46 +03:00
dw_dma_of_controller_register ( chip - > dw ) ;
2013-06-05 15:26:45 +03:00
2019-08-20 16:15:44 +03:00
dw_dma_acpi_controller_register ( chip - > dw ) ;
2013-06-05 15:26:45 +03:00
return 0 ;
2014-08-19 20:29:17 +03:00
err_dw_dma_probe :
2015-01-13 18:57:15 +02:00
pm_runtime_disable ( & pdev - > dev ) ;
2014-08-19 20:29:17 +03:00
clk_disable_unprepare ( chip - > clk ) ;
return err ;
2013-06-05 15:26:45 +03:00
}
static int dw_remove ( struct platform_device * pdev )
{
2019-08-20 16:15:40 +03:00
struct dw_dma_chip_pdata * data = platform_get_drvdata ( pdev ) ;
struct dw_dma_chip * chip = data - > chip ;
int ret ;
2013-06-05 15:26:45 +03:00
2019-08-20 16:15:44 +03:00
dw_dma_acpi_controller_free ( chip - > dw ) ;
2019-08-20 16:15:43 +03:00
2019-08-20 16:15:46 +03:00
dw_dma_of_controller_free ( chip - > dw ) ;
2013-06-05 15:26:45 +03:00
2019-08-20 16:15:40 +03:00
ret = data - > remove ( chip ) ;
if ( ret )
dev_warn ( chip - > dev , " can't remove device properly: %d \n " , ret ) ;
2015-01-13 18:57:15 +02:00
pm_runtime_disable ( & pdev - > dev ) ;
2014-08-19 20:29:17 +03:00
clk_disable_unprepare ( chip - > clk ) ;
return 0 ;
2013-06-05 15:26:45 +03:00
}
static void dw_shutdown ( struct platform_device * pdev )
{
2019-08-20 16:15:40 +03:00
struct dw_dma_chip_pdata * data = platform_get_drvdata ( pdev ) ;
struct dw_dma_chip * chip = data - > chip ;
2013-06-05 15:26:45 +03:00
2015-12-04 23:49:23 +02:00
/*
2019-01-07 13:07:38 +02:00
* We have to call do_dw_dma_disable ( ) to stop any ongoing transfer . On
2015-12-04 23:49:23 +02:00
* some platforms we can ' t do that since DMA device is powered off .
* Moreover we have no possibility to check if the platform is affected
* or not . That ' s why we call pm_runtime_get_sync ( ) / pm_runtime_put ( )
* unconditionally . On the other hand we can ' t use
* pm_runtime_suspended ( ) because runtime PM framework is not fully
* used by the driver .
*/
pm_runtime_get_sync ( chip - > dev ) ;
2019-01-07 13:07:38 +02:00
do_dw_dma_disable ( chip ) ;
2015-12-04 23:49:23 +02:00
pm_runtime_put_sync_suspend ( chip - > dev ) ;
2014-08-19 20:29:17 +03:00
clk_disable_unprepare ( chip - > clk ) ;
2013-06-05 15:26:45 +03:00
}
# ifdef CONFIG_OF
static const struct of_device_id dw_dma_of_id_table [ ] = {
2019-08-20 16:15:40 +03:00
{ . compatible = " snps,dma-spear1340 " , . data = & dw_dma_chip_pdata } ,
2013-06-05 15:26:45 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , dw_dma_of_id_table ) ;
# endif
# ifdef CONFIG_ACPI
static const struct acpi_device_id dw_dma_acpi_id_table [ ] = {
2019-08-20 16:15:40 +03:00
{ " INTL9C60 " , ( kernel_ulong_t ) & dw_dma_chip_pdata } ,
{ " 80862286 " , ( kernel_ulong_t ) & dw_dma_chip_pdata } ,
{ " 808622C0 " , ( kernel_ulong_t ) & dw_dma_chip_pdata } ,
2019-08-20 16:15:41 +03:00
/* Elkhart Lake iDMA 32-bit (PSE DMA) */
2021-07-12 14:39:40 +03:00
{ " 80864BB4 " , ( kernel_ulong_t ) & xbar_chip_pdata } ,
{ " 80864BB5 " , ( kernel_ulong_t ) & xbar_chip_pdata } ,
{ " 80864BB6 " , ( kernel_ulong_t ) & xbar_chip_pdata } ,
2019-08-20 16:15:41 +03:00
2013-06-05 15:26:45 +03:00
{ }
} ;
2013-07-15 15:04:37 +03:00
MODULE_DEVICE_TABLE ( acpi , dw_dma_acpi_id_table ) ;
2013-06-05 15:26:45 +03:00
# endif
# ifdef CONFIG_PM_SLEEP
2014-04-15 16:18:41 +03:00
static int dw_suspend_late ( struct device * dev )
2013-06-05 15:26:45 +03:00
{
2019-08-20 16:15:40 +03:00
struct dw_dma_chip_pdata * data = dev_get_drvdata ( dev ) ;
struct dw_dma_chip * chip = data - > chip ;
2013-06-05 15:26:45 +03:00
2019-01-07 13:07:38 +02:00
do_dw_dma_disable ( chip ) ;
2014-08-19 20:29:17 +03:00
clk_disable_unprepare ( chip - > clk ) ;
return 0 ;
2013-06-05 15:26:45 +03:00
}
2014-04-15 16:18:41 +03:00
static int dw_resume_early ( struct device * dev )
2013-06-05 15:26:45 +03:00
{
2019-08-20 16:15:40 +03:00
struct dw_dma_chip_pdata * data = dev_get_drvdata ( dev ) ;
struct dw_dma_chip * chip = data - > chip ;
2017-05-22 16:01:48 +05:30
int ret ;
ret = clk_prepare_enable ( chip - > clk ) ;
if ( ret )
return ret ;
2013-06-05 15:26:45 +03:00
2019-01-07 13:07:38 +02:00
return do_dw_dma_enable ( chip ) ;
2013-06-05 15:26:45 +03:00
}
2014-04-15 16:18:41 +03:00
# endif /* CONFIG_PM_SLEEP */
2013-06-05 15:26:45 +03:00
static const struct dev_pm_ops dw_dev_pm_ops = {
2014-04-15 16:18:41 +03:00
SET_LATE_SYSTEM_SLEEP_PM_OPS ( dw_suspend_late , dw_resume_early )
2013-06-05 15:26:45 +03:00
} ;
static struct platform_driver dw_driver = {
. probe = dw_probe ,
. remove = dw_remove ,
2014-09-23 17:18:13 +03:00
. shutdown = dw_shutdown ,
2013-06-05 15:26:45 +03:00
. driver = {
2015-03-09 12:16:42 +02:00
. name = DRV_NAME ,
2013-06-05 15:26:45 +03:00
. pm = & dw_dev_pm_ops ,
. of_match_table = of_match_ptr ( dw_dma_of_id_table ) ,
. acpi_match_table = ACPI_PTR ( dw_dma_acpi_id_table ) ,
} ,
} ;
static int __init dw_init ( void )
{
return platform_driver_register ( & dw_driver ) ;
}
subsys_initcall ( dw_init ) ;
static void __exit dw_exit ( void )
{
platform_driver_unregister ( & dw_driver ) ;
}
module_exit ( dw_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " Synopsys DesignWare DMA Controller platform driver " ) ;
2015-03-09 12:16:42 +02:00
MODULE_ALIAS ( " platform: " DRV_NAME ) ;