22/*
33 * Copyright (c) 2017-2022 Linaro Ltd
44 * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
5+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
56 */
67#include <linux/bits.h>
78#include <linux/bitfield.h>
1718#define LPG_SUBTYPE_REG 0x05
1819#define LPG_SUBTYPE_LPG 0x2
1920#define LPG_SUBTYPE_PWM 0xb
21+ #define LPG_SUBTYPE_HI_RES_PWM 0xc
2022#define LPG_SUBTYPE_LPG_LITE 0x11
2123#define LPG_PATTERN_CONFIG_REG 0x40
2224#define LPG_SIZE_CLK_REG 0x41
2325#define PWM_CLK_SELECT_MASK GENMASK(1, 0)
26+ #define PWM_CLK_SELECT_HI_RES_MASK GENMASK(2, 0)
27+ #define PWM_SIZE_HI_RES_MASK GENMASK(6, 4)
2428#define LPG_PREDIV_CLK_REG 0x42
2529#define PWM_FREQ_PRE_DIV_MASK GENMASK(6, 5)
2630#define PWM_FREQ_EXP_MASK GENMASK(2, 0)
4347#define LPG_LUT_REG (x ) (0x40 + (x) * 2)
4448#define RAMP_CONTROL_REG 0xc8
4549
46- #define LPG_RESOLUTION 512
50+ #define LPG_RESOLUTION_9BIT BIT(9)
51+ #define LPG_RESOLUTION_15BIT BIT(15)
4752#define LPG_MAX_M 7
53+ #define LPG_MAX_PREDIV 6
4854
4955struct lpg_channel ;
5056struct lpg_data ;
@@ -106,6 +112,7 @@ struct lpg {
106112 * @clk_sel: reference clock frequency selector
107113 * @pre_div_sel: divider selector of the reference clock
108114 * @pre_div_exp: exponential divider of the reference clock
115+ * @pwm_resolution_sel: pwm resolution selector
109116 * @ramp_enabled: duty cycle is driven by iterating over lookup table
110117 * @ramp_ping_pong: reverse through pattern, rather than wrapping to start
111118 * @ramp_oneshot: perform only a single pass over the pattern
@@ -138,6 +145,7 @@ struct lpg_channel {
138145 unsigned int clk_sel ;
139146 unsigned int pre_div_sel ;
140147 unsigned int pre_div_exp ;
148+ unsigned int pwm_resolution_sel ;
141149
142150 bool ramp_enabled ;
143151 bool ramp_ping_pong ;
@@ -253,17 +261,24 @@ static int lpg_lut_sync(struct lpg *lpg, unsigned int mask)
253261}
254262
255263static const unsigned int lpg_clk_rates [] = {0 , 1024 , 32768 , 19200000 };
264+ static const unsigned int lpg_clk_rates_hi_res [] = {0 , 1024 , 32768 , 19200000 , 76800000 };
256265static const unsigned int lpg_pre_divs [] = {1 , 3 , 5 , 6 };
266+ static const unsigned int lpg_pwm_resolution [] = {9 };
267+ static const unsigned int lpg_pwm_resolution_hi_res [] = {8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 };
257268
258269static int lpg_calc_freq (struct lpg_channel * chan , uint64_t period )
259270{
260- unsigned int clk_sel , best_clk = 0 ;
271+ unsigned int i , pwm_resolution_count , best_pwm_resolution_sel = 0 ;
272+ const unsigned int * clk_rate_arr , * pwm_resolution_arr ;
273+ unsigned int clk_sel , clk_len , best_clk = 0 ;
261274 unsigned int div , best_div = 0 ;
262275 unsigned int m , best_m = 0 ;
276+ unsigned int resolution ;
263277 unsigned int error ;
264278 unsigned int best_err = UINT_MAX ;
279+ u64 max_period , min_period ;
265280 u64 best_period = 0 ;
266- u64 max_period ;
281+ u64 max_res ;
267282
268283 /*
269284 * The PWM period is determined by:
@@ -272,73 +287,107 @@ static int lpg_calc_freq(struct lpg_channel *chan, uint64_t period)
272287 * period = --------------------------
273288 * refclk
274289 *
275- * With resolution fixed at 2^9 bits, pre_div = {1, 3, 5, 6} and
290+ * Resolution = 2^9 bits for PWM or
291+ * 2^{8, 9, 10, 11, 12, 13, 14, 15} bits for high resolution PWM
292+ * pre_div = {1, 3, 5, 6} and
276293 * M = [0..7].
277294 *
278- * This allows for periods between 27uS and 384s, as the PWM framework
279- * wants a period of equal or lower length than requested, reject
280- * anything below 27uS.
295+ * This allows for periods between 27uS and 384s for PWM channels and periods between
296+ * 3uS and 24576s for high resolution PWMs.
297+ * The PWM framework wants a period of equal or lower length than requested,
298+ * reject anything below minimum period.
281299 */
282- if (period <= (u64 )NSEC_PER_SEC * LPG_RESOLUTION / 19200000 )
300+
301+ if (chan -> subtype == LPG_SUBTYPE_HI_RES_PWM ) {
302+ clk_rate_arr = lpg_clk_rates_hi_res ;
303+ clk_len = ARRAY_SIZE (lpg_clk_rates_hi_res );
304+ pwm_resolution_arr = lpg_pwm_resolution_hi_res ;
305+ pwm_resolution_count = ARRAY_SIZE (lpg_pwm_resolution_hi_res );
306+ max_res = LPG_RESOLUTION_15BIT ;
307+ } else {
308+ clk_rate_arr = lpg_clk_rates ;
309+ clk_len = ARRAY_SIZE (lpg_clk_rates );
310+ pwm_resolution_arr = lpg_pwm_resolution ;
311+ pwm_resolution_count = ARRAY_SIZE (lpg_pwm_resolution );
312+ max_res = LPG_RESOLUTION_9BIT ;
313+ }
314+
315+ min_period = (u64 )NSEC_PER_SEC *
316+ div64_u64 ((1 << pwm_resolution_arr [0 ]), clk_rate_arr [clk_len - 1 ]);
317+ if (period <= min_period )
283318 return - EINVAL ;
284319
285320 /* Limit period to largest possible value, to avoid overflows */
286- max_period = (u64 )NSEC_PER_SEC * LPG_RESOLUTION * 6 * (1 << LPG_MAX_M ) / 1024 ;
321+ max_period = (u64 )NSEC_PER_SEC * max_res * LPG_MAX_PREDIV *
322+ div64_u64 ((1 << LPG_MAX_M ), 1024 );
287323 if (period > max_period )
288324 period = max_period ;
289325
290326 /*
291- * Search for the pre_div, refclk and M by solving the rewritten formula
292- * for each refclk and pre_div value:
327+ * Search for the pre_div, refclk, resolution and M by solving the rewritten formula
328+ * for each refclk, resolution and pre_div value:
293329 *
294330 * period * refclk
295331 * M = log2 -------------------------------------
296332 * NSEC_PER_SEC * pre_div * resolution
297333 */
298- for (clk_sel = 1 ; clk_sel < ARRAY_SIZE (lpg_clk_rates ); clk_sel ++ ) {
299- u64 numerator = period * lpg_clk_rates [clk_sel ];
300-
301- for (div = 0 ; div < ARRAY_SIZE (lpg_pre_divs ); div ++ ) {
302- u64 denominator = (u64 )NSEC_PER_SEC * lpg_pre_divs [div ] * LPG_RESOLUTION ;
303- u64 actual ;
304- u64 ratio ;
305-
306- if (numerator < denominator )
307- continue ;
308-
309- ratio = div64_u64 (numerator , denominator );
310- m = ilog2 (ratio );
311- if (m > LPG_MAX_M )
312- m = LPG_MAX_M ;
313-
314- actual = DIV_ROUND_UP_ULL (denominator * (1 << m ), lpg_clk_rates [clk_sel ]);
315-
316- error = period - actual ;
317- if (error < best_err ) {
318- best_err = error ;
319334
320- best_div = div ;
321- best_m = m ;
322- best_clk = clk_sel ;
323- best_period = actual ;
335+ for (i = 0 ; i < pwm_resolution_count ; i ++ ) {
336+ resolution = 1 << pwm_resolution_arr [i ];
337+ for (clk_sel = 1 ; clk_sel < clk_len ; clk_sel ++ ) {
338+ u64 numerator = period * clk_rate_arr [clk_sel ];
339+
340+ for (div = 0 ; div < ARRAY_SIZE (lpg_pre_divs ); div ++ ) {
341+ u64 denominator = (u64 )NSEC_PER_SEC * lpg_pre_divs [div ] *
342+ resolution ;
343+ u64 actual ;
344+ u64 ratio ;
345+
346+ if (numerator < denominator )
347+ continue ;
348+
349+ ratio = div64_u64 (numerator , denominator );
350+ m = ilog2 (ratio );
351+ if (m > LPG_MAX_M )
352+ m = LPG_MAX_M ;
353+
354+ actual = DIV_ROUND_UP_ULL (denominator * (1 << m ),
355+ clk_rate_arr [clk_sel ]);
356+ error = period - actual ;
357+ if (error < best_err ) {
358+ best_err = error ;
359+ best_div = div ;
360+ best_m = m ;
361+ best_clk = clk_sel ;
362+ best_period = actual ;
363+ best_pwm_resolution_sel = i ;
364+ }
324365 }
325366 }
326367 }
327-
328368 chan -> clk_sel = best_clk ;
329369 chan -> pre_div_sel = best_div ;
330370 chan -> pre_div_exp = best_m ;
331371 chan -> period = best_period ;
332-
372+ chan -> pwm_resolution_sel = best_pwm_resolution_sel ;
333373 return 0 ;
334374}
335375
336376static void lpg_calc_duty (struct lpg_channel * chan , uint64_t duty )
337377{
338- unsigned int max = LPG_RESOLUTION - 1 ;
378+ unsigned int max ;
339379 unsigned int val ;
380+ unsigned int clk_rate ;
381+
382+ if (chan -> subtype == LPG_SUBTYPE_HI_RES_PWM ) {
383+ max = LPG_RESOLUTION_15BIT - 1 ;
384+ clk_rate = lpg_clk_rates_hi_res [chan -> clk_sel ];
385+ } else {
386+ max = LPG_RESOLUTION_9BIT - 1 ;
387+ clk_rate = lpg_clk_rates [chan -> clk_sel ];
388+ }
340389
341- val = div64_u64 (duty * lpg_clk_rates [ chan -> clk_sel ] ,
390+ val = div64_u64 (duty * clk_rate ,
342391 (u64 )NSEC_PER_SEC * lpg_pre_divs [chan -> pre_div_sel ] * (1 << chan -> pre_div_exp ));
343392
344393 chan -> pwm_value = min (val , max );
@@ -354,14 +403,17 @@ static void lpg_apply_freq(struct lpg_channel *chan)
354403
355404 val = chan -> clk_sel ;
356405
357- /* Specify 9bit resolution, based on the subtype of the channel */
406+ /* Specify resolution, based on the subtype of the channel */
358407 switch (chan -> subtype ) {
359408 case LPG_SUBTYPE_LPG :
360409 val |= GENMASK (5 , 4 );
361410 break ;
362411 case LPG_SUBTYPE_PWM :
363412 val |= BIT (2 );
364413 break ;
414+ case LPG_SUBTYPE_HI_RES_PWM :
415+ val |= FIELD_PREP (PWM_SIZE_HI_RES_MASK , chan -> pwm_resolution_sel );
416+ break ;
365417 case LPG_SUBTYPE_LPG_LITE :
366418 default :
367419 val |= BIT (4 );
@@ -670,7 +722,7 @@ static int lpg_blink_set(struct lpg_led *led,
670722 triled_set (lpg , triled_mask , triled_mask );
671723
672724 chan = led -> channels [0 ];
673- duty = div_u64 (chan -> pwm_value * chan -> period , LPG_RESOLUTION );
725+ duty = div_u64 (chan -> pwm_value * chan -> period , LPG_RESOLUTION_9BIT );
674726 * delay_on = div_u64 (duty , NSEC_PER_MSEC );
675727 * delay_off = div_u64 (chan -> period - duty , NSEC_PER_MSEC );
676728
@@ -977,6 +1029,7 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
9771029{
9781030 struct lpg * lpg = container_of (chip , struct lpg , pwm );
9791031 struct lpg_channel * chan = & lpg -> channels [pwm -> hwpwm ];
1032+ unsigned int resolution ;
9801033 unsigned int pre_div ;
9811034 unsigned int refclk ;
9821035 unsigned int val ;
@@ -988,7 +1041,14 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
9881041 if (ret )
9891042 return ret ;
9901043
991- refclk = lpg_clk_rates [val & PWM_CLK_SELECT_MASK ];
1044+ if (chan -> subtype == LPG_SUBTYPE_HI_RES_PWM ) {
1045+ refclk = lpg_clk_rates_hi_res [FIELD_GET (PWM_CLK_SELECT_HI_RES_MASK , val )];
1046+ resolution = lpg_pwm_resolution_hi_res [FIELD_GET (PWM_SIZE_HI_RES_MASK , val )];
1047+ } else {
1048+ refclk = lpg_clk_rates [FIELD_GET (PWM_CLK_SELECT_MASK , val )];
1049+ resolution = 9 ;
1050+ }
1051+
9921052 if (refclk ) {
9931053 ret = regmap_read (lpg -> map , chan -> base + LPG_PREDIV_CLK_REG , & val );
9941054 if (ret )
@@ -1001,7 +1061,8 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
10011061 if (ret )
10021062 return ret ;
10031063
1004- state -> period = DIV_ROUND_UP_ULL ((u64 )NSEC_PER_SEC * LPG_RESOLUTION * pre_div * (1 << m ), refclk );
1064+ state -> period = DIV_ROUND_UP_ULL ((u64 )NSEC_PER_SEC * (1 << resolution ) *
1065+ pre_div * (1 << m ), refclk );
10051066 state -> duty_cycle = DIV_ROUND_UP_ULL ((u64 )NSEC_PER_SEC * pwm_value * pre_div * (1 << m ), refclk );
10061067 } else {
10071068 state -> period = 0 ;
@@ -1149,7 +1210,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
11491210 }
11501211
11511212 cdev -> default_trigger = of_get_property (np , "linux,default-trigger" , NULL );
1152- cdev -> max_brightness = LPG_RESOLUTION - 1 ;
1213+ cdev -> max_brightness = LPG_RESOLUTION_9BIT - 1 ;
11531214
11541215 if (!of_property_read_string (np , "default-state" , & state ) &&
11551216 !strcmp (state , "on" ))
0 commit comments