2019-05-28 19:57:07 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-01-09 20:54:47 +03:00
/*
* Imagination Technologies Pulse Width Modulator driver
*
* Copyright ( c ) 2014 - 2015 , Imagination Technologies
*
* Based on drivers / pwm / pwm - tegra . c , Copyright ( c ) 2010 , NVIDIA Corporation
*/
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/of.h>
2015-05-09 00:47:31 +03:00
# include <linux/of_device.h>
2015-01-09 20:54:47 +03:00
# include <linux/platform_device.h>
2017-10-02 12:51:48 +03:00
# include <linux/pm_runtime.h>
2015-01-09 20:54:47 +03:00
# include <linux/pwm.h>
# include <linux/regmap.h>
# include <linux/slab.h>
/* PWM registers */
# define PWM_CTRL_CFG 0x0000
# define PWM_CTRL_CFG_NO_SUB_DIV 0
# define PWM_CTRL_CFG_SUB_DIV0 1
# define PWM_CTRL_CFG_SUB_DIV1 2
# define PWM_CTRL_CFG_SUB_DIV0_DIV1 3
# define PWM_CTRL_CFG_DIV_SHIFT(ch) ((ch) * 2 + 4)
# define PWM_CTRL_CFG_DIV_MASK 0x3
# define PWM_CH_CFG(ch) (0x4 + (ch) * 4)
# define PWM_CH_CFG_TMBASE_SHIFT 0
# define PWM_CH_CFG_DUTY_SHIFT 16
# define PERIP_PWM_PDM_CONTROL 0x0140
# define PERIP_PWM_PDM_CONTROL_CH_MASK 0x1
# define PERIP_PWM_PDM_CONTROL_CH_SHIFT(ch) ((ch) * 4)
2017-10-02 12:51:48 +03:00
# define IMG_PWM_PM_TIMEOUT 1000 /* ms */
2015-05-09 00:47:31 +03:00
/*
* PWM period is specified with a timebase register ,
* in number of step periods . The PWM duty cycle is also
* specified in step periods , in the [ 0 , $ timebase ] range .
* In other words , the timebase imposes the duty cycle
* resolution . Therefore , let ' s constraint the timebase to
* a minimum value to allow a sane range of duty cycle values .
* Imposing a minimum timebase , will impose a maximum PWM frequency .
*
* The value chosen is completely arbitrary .
*/
# define MIN_TMBASE_STEPS 16
2017-10-02 12:51:47 +03:00
# define IMG_PWM_NPWM 4
2015-05-09 00:47:31 +03:00
struct img_pwm_soc_data {
u32 max_timebase ;
} ;
2015-01-09 20:54:47 +03:00
struct img_pwm_chip {
struct device * dev ;
struct pwm_chip chip ;
struct clk * pwm_clk ;
struct clk * sys_clk ;
void __iomem * base ;
struct regmap * periph_regs ;
2015-05-09 00:47:31 +03:00
int max_period_ns ;
int min_period_ns ;
const struct img_pwm_soc_data * data ;
2017-10-02 12:51:47 +03:00
u32 suspend_ctrl_cfg ;
u32 suspend_ch_cfg [ IMG_PWM_NPWM ] ;
2015-01-09 20:54:47 +03:00
} ;
static inline struct img_pwm_chip * to_img_pwm_chip ( struct pwm_chip * chip )
{
return container_of ( chip , struct img_pwm_chip , chip ) ;
}
2021-11-23 12:29:35 +03:00
static inline void img_pwm_writel ( struct img_pwm_chip * imgchip ,
2015-01-09 20:54:47 +03:00
u32 reg , u32 val )
{
2021-11-23 12:29:35 +03:00
writel ( val , imgchip - > base + reg ) ;
2015-01-09 20:54:47 +03:00
}
2021-11-23 12:29:35 +03:00
static inline u32 img_pwm_readl ( struct img_pwm_chip * imgchip , u32 reg )
2015-01-09 20:54:47 +03:00
{
2021-11-23 12:29:35 +03:00
return readl ( imgchip - > base + reg ) ;
2015-01-09 20:54:47 +03:00
}
static int img_pwm_config ( struct pwm_chip * chip , struct pwm_device * pwm ,
int duty_ns , int period_ns )
{
u32 val , div , duty , timebase ;
unsigned long mul , output_clk_hz , input_clk_hz ;
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = to_img_pwm_chip ( chip ) ;
unsigned int max_timebase = imgchip - > data - > max_timebase ;
2017-10-02 12:51:48 +03:00
int ret ;
2015-05-09 00:47:31 +03:00
2021-11-23 12:29:35 +03:00
if ( period_ns < imgchip - > min_period_ns | |
period_ns > imgchip - > max_period_ns ) {
2015-05-09 00:47:31 +03:00
dev_err ( chip - > dev , " configured period not in range \n " ) ;
return - ERANGE ;
}
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
input_clk_hz = clk_get_rate ( imgchip - > pwm_clk ) ;
2015-01-09 20:54:47 +03:00
output_clk_hz = DIV_ROUND_UP ( NSEC_PER_SEC , period_ns ) ;
mul = DIV_ROUND_UP ( input_clk_hz , output_clk_hz ) ;
2015-05-09 00:47:31 +03:00
if ( mul < = max_timebase ) {
2015-01-09 20:54:47 +03:00
div = PWM_CTRL_CFG_NO_SUB_DIV ;
timebase = DIV_ROUND_UP ( mul , 1 ) ;
2015-05-09 00:47:31 +03:00
} else if ( mul < = max_timebase * 8 ) {
2015-01-09 20:54:47 +03:00
div = PWM_CTRL_CFG_SUB_DIV0 ;
timebase = DIV_ROUND_UP ( mul , 8 ) ;
2015-05-09 00:47:31 +03:00
} else if ( mul < = max_timebase * 64 ) {
2015-01-09 20:54:47 +03:00
div = PWM_CTRL_CFG_SUB_DIV1 ;
timebase = DIV_ROUND_UP ( mul , 64 ) ;
2015-05-09 00:47:31 +03:00
} else if ( mul < = max_timebase * 512 ) {
2015-01-09 20:54:47 +03:00
div = PWM_CTRL_CFG_SUB_DIV0_DIV1 ;
timebase = DIV_ROUND_UP ( mul , 512 ) ;
2019-03-08 01:36:28 +03:00
} else {
2015-01-09 20:54:47 +03:00
dev_err ( chip - > dev ,
" failed to configure timebase steps/divider value \n " ) ;
return - EINVAL ;
}
duty = DIV_ROUND_UP ( timebase * duty_ns , period_ns ) ;
2021-11-12 22:00:15 +03:00
ret = pm_runtime_resume_and_get ( chip - > dev ) ;
if ( ret < 0 )
2017-10-02 12:51:48 +03:00
return ret ;
2021-11-23 12:29:35 +03:00
val = img_pwm_readl ( imgchip , PWM_CTRL_CFG ) ;
2015-01-09 20:54:47 +03:00
val & = ~ ( PWM_CTRL_CFG_DIV_MASK < < PWM_CTRL_CFG_DIV_SHIFT ( pwm - > hwpwm ) ) ;
val | = ( div & PWM_CTRL_CFG_DIV_MASK ) < <
PWM_CTRL_CFG_DIV_SHIFT ( pwm - > hwpwm ) ;
2021-11-23 12:29:35 +03:00
img_pwm_writel ( imgchip , PWM_CTRL_CFG , val ) ;
2015-01-09 20:54:47 +03:00
val = ( duty < < PWM_CH_CFG_DUTY_SHIFT ) |
( timebase < < PWM_CH_CFG_TMBASE_SHIFT ) ;
2021-11-23 12:29:35 +03:00
img_pwm_writel ( imgchip , PWM_CH_CFG ( pwm - > hwpwm ) , val ) ;
2015-01-09 20:54:47 +03:00
2017-10-02 12:51:48 +03:00
pm_runtime_mark_last_busy ( chip - > dev ) ;
pm_runtime_put_autosuspend ( chip - > dev ) ;
2015-01-09 20:54:47 +03:00
return 0 ;
}
static int img_pwm_enable ( struct pwm_chip * chip , struct pwm_device * pwm )
{
u32 val ;
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = to_img_pwm_chip ( chip ) ;
2017-10-02 12:51:48 +03:00
int ret ;
2021-05-12 06:57:17 +03:00
ret = pm_runtime_resume_and_get ( chip - > dev ) ;
2017-10-02 12:51:48 +03:00
if ( ret < 0 )
return ret ;
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
val = img_pwm_readl ( imgchip , PWM_CTRL_CFG ) ;
2015-01-09 20:54:47 +03:00
val | = BIT ( pwm - > hwpwm ) ;
2021-11-23 12:29:35 +03:00
img_pwm_writel ( imgchip , PWM_CTRL_CFG , val ) ;
2015-01-09 20:54:47 +03:00
pwm: img: Use regmap_clear_bits and regmap_set_bits where applicable
Found using coccinelle and the following semantic patch:
@@
expression map, reg, bits;
@@
- regmap_update_bits(map, reg, bits, bits)
+ regmap_set_bits(map, reg, bits)
@@
expression map, reg, bits;
@@
- regmap_update_bits(map, reg, bits, 0)
+ regmap_clear_bits(map, reg, bits)
Link: https://lore.kernel.org/r/20221115111347.3705732-3-u.kleine-koenig@pengutronix.de
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2022-12-02 21:35:15 +03:00
regmap_clear_bits ( imgchip - > periph_regs , PERIP_PWM_PDM_CONTROL ,
PERIP_PWM_PDM_CONTROL_CH_MASK < <
PERIP_PWM_PDM_CONTROL_CH_SHIFT ( pwm - > hwpwm ) ) ;
2015-01-09 20:54:47 +03:00
return 0 ;
}
static void img_pwm_disable ( struct pwm_chip * chip , struct pwm_device * pwm )
{
u32 val ;
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = to_img_pwm_chip ( chip ) ;
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
val = img_pwm_readl ( imgchip , PWM_CTRL_CFG ) ;
2015-01-09 20:54:47 +03:00
val & = ~ BIT ( pwm - > hwpwm ) ;
2021-11-23 12:29:35 +03:00
img_pwm_writel ( imgchip , PWM_CTRL_CFG , val ) ;
2017-10-02 12:51:48 +03:00
pm_runtime_mark_last_busy ( chip - > dev ) ;
pm_runtime_put_autosuspend ( chip - > dev ) ;
2015-01-09 20:54:47 +03:00
}
2021-10-29 13:56:17 +03:00
static int img_pwm_apply ( struct pwm_chip * chip , struct pwm_device * pwm ,
const struct pwm_state * state )
{
int err ;
if ( state - > polarity ! = PWM_POLARITY_NORMAL )
return - EINVAL ;
if ( ! state - > enabled ) {
if ( pwm - > state . enabled )
img_pwm_disable ( chip , pwm ) ;
return 0 ;
}
err = img_pwm_config ( pwm - > chip , pwm , state - > duty_cycle , state - > period ) ;
if ( err )
return err ;
if ( ! pwm - > state . enabled )
err = img_pwm_enable ( chip , pwm ) ;
return err ;
}
2015-01-09 20:54:47 +03:00
static const struct pwm_ops img_pwm_ops = {
2021-10-29 13:56:17 +03:00
. apply = img_pwm_apply ,
2015-01-09 20:54:47 +03:00
. owner = THIS_MODULE ,
} ;
2015-05-09 00:47:31 +03:00
static const struct img_pwm_soc_data pistachio_pwm = {
. max_timebase = 255 ,
} ;
static const struct of_device_id img_pwm_of_match [ ] = {
{
. compatible = " img,pistachio-pwm " ,
. data = & pistachio_pwm ,
} ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , img_pwm_of_match ) ;
2017-10-02 12:51:48 +03:00
static int img_pwm_runtime_suspend ( struct device * dev )
{
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = dev_get_drvdata ( dev ) ;
2017-10-02 12:51:48 +03:00
2021-11-23 12:29:35 +03:00
clk_disable_unprepare ( imgchip - > pwm_clk ) ;
clk_disable_unprepare ( imgchip - > sys_clk ) ;
2017-10-02 12:51:48 +03:00
return 0 ;
}
static int img_pwm_runtime_resume ( struct device * dev )
{
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = dev_get_drvdata ( dev ) ;
2017-10-02 12:51:48 +03:00
int ret ;
2021-11-23 12:29:35 +03:00
ret = clk_prepare_enable ( imgchip - > sys_clk ) ;
2017-10-02 12:51:48 +03:00
if ( ret < 0 ) {
dev_err ( dev , " could not prepare or enable sys clock \n " ) ;
return ret ;
}
2021-11-23 12:29:35 +03:00
ret = clk_prepare_enable ( imgchip - > pwm_clk ) ;
2017-10-02 12:51:48 +03:00
if ( ret < 0 ) {
dev_err ( dev , " could not prepare or enable pwm clock \n " ) ;
2021-11-23 12:29:35 +03:00
clk_disable_unprepare ( imgchip - > sys_clk ) ;
2017-10-02 12:51:48 +03:00
return ret ;
}
return 0 ;
}
2015-01-09 20:54:47 +03:00
static int img_pwm_probe ( struct platform_device * pdev )
{
int ret ;
2015-05-09 00:47:31 +03:00
u64 val ;
unsigned long clk_rate ;
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip ;
2015-05-09 00:47:31 +03:00
const struct of_device_id * of_dev_id ;
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
imgchip = devm_kzalloc ( & pdev - > dev , sizeof ( * imgchip ) , GFP_KERNEL ) ;
if ( ! imgchip )
2015-01-09 20:54:47 +03:00
return - ENOMEM ;
2021-11-23 12:29:35 +03:00
imgchip - > dev = & pdev - > dev ;
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
imgchip - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( imgchip - > base ) )
return PTR_ERR ( imgchip - > base ) ;
2015-01-09 20:54:47 +03:00
2015-05-09 00:47:31 +03:00
of_dev_id = of_match_device ( img_pwm_of_match , & pdev - > dev ) ;
if ( ! of_dev_id )
return - ENODEV ;
2021-11-23 12:29:35 +03:00
imgchip - > data = of_dev_id - > data ;
2015-05-09 00:47:31 +03:00
2021-11-23 12:29:35 +03:00
imgchip - > periph_regs = syscon_regmap_lookup_by_phandle ( pdev - > dev . of_node ,
" img,cr-periph " ) ;
if ( IS_ERR ( imgchip - > periph_regs ) )
return PTR_ERR ( imgchip - > periph_regs ) ;
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
imgchip - > sys_clk = devm_clk_get ( & pdev - > dev , " sys " ) ;
if ( IS_ERR ( imgchip - > sys_clk ) ) {
2015-01-09 20:54:47 +03:00
dev_err ( & pdev - > dev , " failed to get system clock \n " ) ;
2021-11-23 12:29:35 +03:00
return PTR_ERR ( imgchip - > sys_clk ) ;
2015-01-09 20:54:47 +03:00
}
2021-11-23 12:29:35 +03:00
imgchip - > pwm_clk = devm_clk_get ( & pdev - > dev , " imgchip " ) ;
if ( IS_ERR ( imgchip - > pwm_clk ) ) {
dev_err ( & pdev - > dev , " failed to get imgchip clock \n " ) ;
return PTR_ERR ( imgchip - > pwm_clk ) ;
2015-01-09 20:54:47 +03:00
}
2021-11-23 12:29:35 +03:00
platform_set_drvdata ( pdev , imgchip ) ;
2020-08-20 20:14:25 +03:00
2017-10-02 12:51:48 +03:00
pm_runtime_set_autosuspend_delay ( & pdev - > dev , IMG_PWM_PM_TIMEOUT ) ;
pm_runtime_use_autosuspend ( & pdev - > dev ) ;
pm_runtime_enable ( & pdev - > dev ) ;
if ( ! pm_runtime_enabled ( & pdev - > dev ) ) {
ret = img_pwm_runtime_resume ( & pdev - > dev ) ;
if ( ret )
goto err_pm_disable ;
2015-01-09 20:54:47 +03:00
}
2021-11-23 12:29:35 +03:00
clk_rate = clk_get_rate ( imgchip - > pwm_clk ) ;
2016-03-03 01:33:34 +03:00
if ( ! clk_rate ) {
2021-11-23 12:29:35 +03:00
dev_err ( & pdev - > dev , " imgchip clock has no frequency \n " ) ;
2016-03-03 01:33:34 +03:00
ret = - EINVAL ;
2017-10-02 12:51:48 +03:00
goto err_suspend ;
2016-03-03 01:33:34 +03:00
}
2015-05-09 00:47:31 +03:00
/* The maximum input clock divider is 512 */
2021-11-23 12:29:35 +03:00
val = ( u64 ) NSEC_PER_SEC * 512 * imgchip - > data - > max_timebase ;
2015-05-09 00:47:31 +03:00
do_div ( val , clk_rate ) ;
2021-11-23 12:29:35 +03:00
imgchip - > max_period_ns = val ;
2015-05-09 00:47:31 +03:00
val = ( u64 ) NSEC_PER_SEC * MIN_TMBASE_STEPS ;
do_div ( val , clk_rate ) ;
2021-11-23 12:29:35 +03:00
imgchip - > min_period_ns = val ;
2015-05-09 00:47:31 +03:00
2021-11-23 12:29:35 +03:00
imgchip - > chip . dev = & pdev - > dev ;
imgchip - > chip . ops = & img_pwm_ops ;
imgchip - > chip . npwm = IMG_PWM_NPWM ;
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
ret = pwmchip_add ( & imgchip - > chip ) ;
2015-01-09 20:54:47 +03:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " pwmchip_add failed: %d \n " , ret ) ;
2017-10-02 12:51:48 +03:00
goto err_suspend ;
2015-01-09 20:54:47 +03:00
}
return 0 ;
2017-10-02 12:51:48 +03:00
err_suspend :
if ( ! pm_runtime_enabled ( & pdev - > dev ) )
img_pwm_runtime_suspend ( & pdev - > dev ) ;
err_pm_disable :
pm_runtime_disable ( & pdev - > dev ) ;
pm_runtime_dont_use_autosuspend ( & pdev - > dev ) ;
2015-01-09 20:54:47 +03:00
return ret ;
}
2023-03-03 21:54:26 +03:00
static void img_pwm_remove ( struct platform_device * pdev )
2015-01-09 20:54:47 +03:00
{
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = platform_get_drvdata ( pdev ) ;
2015-01-09 20:54:47 +03:00
2017-10-02 12:51:48 +03:00
pm_runtime_disable ( & pdev - > dev ) ;
if ( ! pm_runtime_status_suspended ( & pdev - > dev ) )
img_pwm_runtime_suspend ( & pdev - > dev ) ;
2015-01-09 20:54:47 +03:00
2021-11-23 12:29:35 +03:00
pwmchip_remove ( & imgchip - > chip ) ;
2015-01-09 20:54:47 +03:00
}
2017-10-02 12:51:47 +03:00
# ifdef CONFIG_PM_SLEEP
static int img_pwm_suspend ( struct device * dev )
{
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = dev_get_drvdata ( dev ) ;
2017-10-02 12:51:48 +03:00
int i , ret ;
if ( pm_runtime_status_suspended ( dev ) ) {
ret = img_pwm_runtime_resume ( dev ) ;
if ( ret )
return ret ;
}
2017-10-02 12:51:47 +03:00
2021-11-23 12:29:35 +03:00
for ( i = 0 ; i < imgchip - > chip . npwm ; i + + )
imgchip - > suspend_ch_cfg [ i ] = img_pwm_readl ( imgchip ,
PWM_CH_CFG ( i ) ) ;
2017-10-02 12:51:47 +03:00
2021-11-23 12:29:35 +03:00
imgchip - > suspend_ctrl_cfg = img_pwm_readl ( imgchip , PWM_CTRL_CFG ) ;
2017-10-02 12:51:47 +03:00
2017-10-02 12:51:48 +03:00
img_pwm_runtime_suspend ( dev ) ;
2017-10-02 12:51:47 +03:00
return 0 ;
}
static int img_pwm_resume ( struct device * dev )
{
2021-11-23 12:29:35 +03:00
struct img_pwm_chip * imgchip = dev_get_drvdata ( dev ) ;
2017-10-02 12:51:47 +03:00
int ret ;
int i ;
2017-10-02 12:51:48 +03:00
ret = img_pwm_runtime_resume ( dev ) ;
if ( ret )
2017-10-02 12:51:47 +03:00
return ret ;
2021-11-23 12:29:35 +03:00
for ( i = 0 ; i < imgchip - > chip . npwm ; i + + )
img_pwm_writel ( imgchip , PWM_CH_CFG ( i ) ,
imgchip - > suspend_ch_cfg [ i ] ) ;
2017-10-02 12:51:47 +03:00
2021-11-23 12:29:35 +03:00
img_pwm_writel ( imgchip , PWM_CTRL_CFG , imgchip - > suspend_ctrl_cfg ) ;
2017-10-02 12:51:47 +03:00
2021-11-23 12:29:35 +03:00
for ( i = 0 ; i < imgchip - > chip . npwm ; i + + )
if ( imgchip - > suspend_ctrl_cfg & BIT ( i ) )
pwm: img: Use regmap_clear_bits and regmap_set_bits where applicable
Found using coccinelle and the following semantic patch:
@@
expression map, reg, bits;
@@
- regmap_update_bits(map, reg, bits, bits)
+ regmap_set_bits(map, reg, bits)
@@
expression map, reg, bits;
@@
- regmap_update_bits(map, reg, bits, 0)
+ regmap_clear_bits(map, reg, bits)
Link: https://lore.kernel.org/r/20221115111347.3705732-3-u.kleine-koenig@pengutronix.de
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
2022-12-02 21:35:15 +03:00
regmap_clear_bits ( imgchip - > periph_regs ,
PERIP_PWM_PDM_CONTROL ,
PERIP_PWM_PDM_CONTROL_CH_MASK < <
PERIP_PWM_PDM_CONTROL_CH_SHIFT ( i ) ) ;
2017-10-02 12:51:47 +03:00
2017-10-02 12:51:48 +03:00
if ( pm_runtime_status_suspended ( dev ) )
img_pwm_runtime_suspend ( dev ) ;
2017-10-02 12:51:47 +03:00
return 0 ;
}
# endif /* CONFIG_PM */
2017-10-02 12:51:48 +03:00
static const struct dev_pm_ops img_pwm_pm_ops = {
SET_RUNTIME_PM_OPS ( img_pwm_runtime_suspend ,
img_pwm_runtime_resume ,
NULL )
SET_SYSTEM_SLEEP_PM_OPS ( img_pwm_suspend , img_pwm_resume )
} ;
2017-10-02 12:51:47 +03:00
2015-01-09 20:54:47 +03:00
static struct platform_driver img_pwm_driver = {
. driver = {
. name = " img-pwm " ,
2017-10-02 12:51:47 +03:00
. pm = & img_pwm_pm_ops ,
2015-01-09 20:54:47 +03:00
. of_match_table = img_pwm_of_match ,
} ,
. probe = img_pwm_probe ,
2023-03-03 21:54:26 +03:00
. remove_new = img_pwm_remove ,
2015-01-09 20:54:47 +03:00
} ;
module_platform_driver ( img_pwm_driver ) ;
MODULE_AUTHOR ( " Sai Masarapu <Sai.Masarapu@imgtec.com> " ) ;
MODULE_DESCRIPTION ( " Imagination Technologies PWM DAC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;