2019-05-31 01:09:32 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2012-07-10 11:38:10 -03:00
/*
* Copyright 2012 Alexandre Pereira da Silva < aletes . xgr @ gmail . com >
*/
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/platform_device.h>
# include <linux/pwm.h>
# include <linux/slab.h>
struct lpc32xx_pwm_chip {
struct pwm_chip chip ;
struct clk * clk ;
void __iomem * base ;
} ;
2015-12-06 13:32:01 +02:00
# define PWM_ENABLE BIT(31)
2016-06-27 09:09:55 -04:00
# define PWM_PIN_LEVEL BIT(30)
2012-07-10 11:38:10 -03:00
# define to_lpc32xx_pwm_chip(_chip) \
container_of ( _chip , struct lpc32xx_pwm_chip , chip )
static int lpc32xx_pwm_config ( struct pwm_chip * chip , struct pwm_device * pwm ,
int duty_ns , int period_ns )
{
struct lpc32xx_pwm_chip * lpc32xx = to_lpc32xx_pwm_chip ( chip ) ;
unsigned long long c ;
int period_cycles , duty_cycles ;
2013-04-23 14:02:49 +08:00
u32 val ;
2015-12-06 13:32:01 +02:00
c = clk_get_rate ( lpc32xx - > clk ) ;
2012-07-10 11:38:10 -03:00
2015-12-06 13:32:01 +02:00
/* The highest acceptable divisor is 256, which is represented by 0 */
period_cycles = div64_u64 ( c * period_ns ,
( unsigned long long ) NSEC_PER_SEC * 256 ) ;
2015-12-06 13:32:02 +02:00
if ( ! period_cycles | | period_cycles > 256 )
return - ERANGE ;
if ( period_cycles = = 256 )
2015-12-06 13:32:01 +02:00
period_cycles = 0 ;
2012-07-10 11:38:10 -03:00
2015-12-06 13:32:01 +02:00
/* Compute 256 x #duty/period value and care for corner cases */
duty_cycles = div64_u64 ( ( unsigned long long ) ( period_ns - duty_ns ) * 256 ,
period_ns ) ;
if ( ! duty_cycles )
duty_cycles = 1 ;
if ( duty_cycles > 255 )
duty_cycles = 255 ;
2012-07-10 11:38:10 -03:00
2023-07-17 17:52:57 +02:00
val = readl ( lpc32xx - > base ) ;
2013-04-23 14:02:49 +08:00
val & = ~ 0xFFFF ;
2015-12-06 13:32:01 +02:00
val | = ( period_cycles < < 8 ) | duty_cycles ;
2023-07-17 17:52:57 +02:00
writel ( val , lpc32xx - > base ) ;
2012-07-10 11:38:10 -03:00
return 0 ;
}
static int lpc32xx_pwm_enable ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct lpc32xx_pwm_chip * lpc32xx = to_lpc32xx_pwm_chip ( chip ) ;
2013-04-23 14:01:31 +08:00
u32 val ;
int ret ;
2015-12-06 13:32:00 +02:00
ret = clk_prepare_enable ( lpc32xx - > clk ) ;
2013-04-23 14:01:31 +08:00
if ( ret )
return ret ;
2023-07-17 17:52:57 +02:00
val = readl ( lpc32xx - > base ) ;
2013-04-23 14:01:31 +08:00
val | = PWM_ENABLE ;
2023-07-17 17:52:57 +02:00
writel ( val , lpc32xx - > base ) ;
2012-07-10 11:38:10 -03:00
2013-04-23 14:01:31 +08:00
return 0 ;
2012-07-10 11:38:10 -03:00
}
static void lpc32xx_pwm_disable ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct lpc32xx_pwm_chip * lpc32xx = to_lpc32xx_pwm_chip ( chip ) ;
2013-04-23 14:01:31 +08:00
u32 val ;
2023-07-17 17:52:57 +02:00
val = readl ( lpc32xx - > base ) ;
2013-04-23 14:01:31 +08:00
val & = ~ PWM_ENABLE ;
2023-07-17 17:52:57 +02:00
writel ( val , lpc32xx - > base ) ;
2012-07-10 11:38:10 -03:00
2015-12-06 13:32:00 +02:00
clk_disable_unprepare ( lpc32xx - > clk ) ;
2012-07-10 11:38:10 -03:00
}
2022-05-07 10:29:01 +02:00
static int lpc32xx_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 )
lpc32xx_pwm_disable ( chip , pwm ) ;
return 0 ;
}
2023-12-01 11:22:53 +01:00
err = lpc32xx_pwm_config ( chip , pwm , state - > duty_cycle , state - > period ) ;
2022-05-07 10:29:01 +02:00
if ( err )
return err ;
if ( ! pwm - > state . enabled )
err = lpc32xx_pwm_enable ( chip , pwm ) ;
return err ;
}
2012-07-10 11:38:10 -03:00
static const struct pwm_ops lpc32xx_pwm_ops = {
2022-05-07 10:29:01 +02:00
. apply = lpc32xx_pwm_apply ,
2012-07-10 11:38:10 -03:00
} ;
static int lpc32xx_pwm_probe ( struct platform_device * pdev )
{
struct lpc32xx_pwm_chip * lpc32xx ;
int ret ;
2016-06-27 09:09:55 -04:00
u32 val ;
2012-07-10 11:38:10 -03:00
lpc32xx = devm_kzalloc ( & pdev - > dev , sizeof ( * lpc32xx ) , GFP_KERNEL ) ;
if ( ! lpc32xx )
return - ENOMEM ;
2019-12-29 08:05:51 +00:00
lpc32xx - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2013-01-21 11:09:16 +01:00
if ( IS_ERR ( lpc32xx - > base ) )
return PTR_ERR ( lpc32xx - > base ) ;
2012-07-10 11:38:10 -03:00
lpc32xx - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( lpc32xx - > clk ) )
return PTR_ERR ( lpc32xx - > clk ) ;
lpc32xx - > chip . dev = & pdev - > dev ;
lpc32xx - > chip . ops = & lpc32xx_pwm_ops ;
2015-12-06 13:31:59 +02:00
lpc32xx - > chip . npwm = 1 ;
2012-07-10 11:38:10 -03:00
2021-07-07 18:27:49 +02:00
/* If PWM is disabled, configure the output to the default value */
2023-07-17 17:52:57 +02:00
val = readl ( lpc32xx - > base ) ;
2021-07-07 18:27:49 +02:00
val & = ~ PWM_PIN_LEVEL ;
2023-07-17 17:52:57 +02:00
writel ( val , lpc32xx - > base ) ;
2021-07-07 18:27:49 +02:00
2021-07-07 18:28:10 +02:00
ret = devm_pwmchip_add ( & pdev - > dev , & lpc32xx - > chip ) ;
2012-07-10 11:38:10 -03:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to add PWM chip, error %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
2013-04-18 10:04:14 +02:00
static const struct of_device_id lpc32xx_pwm_dt_ids [ ] = {
2012-07-10 11:38:10 -03:00
{ . compatible = " nxp,lpc3220-pwm " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , lpc32xx_pwm_dt_ids ) ;
static struct platform_driver lpc32xx_pwm_driver = {
. driver = {
. name = " lpc32xx-pwm " ,
2013-09-30 08:56:40 +05:30
. of_match_table = lpc32xx_pwm_dt_ids ,
2012-07-10 11:38:10 -03:00
} ,
. probe = lpc32xx_pwm_probe ,
} ;
module_platform_driver ( lpc32xx_pwm_driver ) ;
MODULE_ALIAS ( " platform:lpc32xx-pwm " ) ;
MODULE_AUTHOR ( " Alexandre Pereira da Silva <aletes.xgr@gmail.com> " ) ;
MODULE_DESCRIPTION ( " LPC32XX PWM Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;