@@ -175,6 +175,80 @@ static int stm32_gate_is_enabled(void __iomem *base,
175175 return (readl (base + gate -> offset ) & BIT (gate -> bit_idx )) != 0 ;
176176}
177177
178+ static unsigned int _get_table_div (const struct clk_div_table * table ,
179+ unsigned int val )
180+ {
181+ const struct clk_div_table * clkt ;
182+
183+ for (clkt = table ; clkt -> div ; clkt ++ )
184+ if (clkt -> val == val )
185+ return clkt -> div ;
186+ return 0 ;
187+ }
188+
189+ static unsigned int _get_div (const struct clk_div_table * table ,
190+ unsigned int val , unsigned long flags , u8 width )
191+ {
192+ if (flags & CLK_DIVIDER_ONE_BASED )
193+ return val ;
194+ if (flags & CLK_DIVIDER_POWER_OF_TWO )
195+ return 1 << val ;
196+ if (table )
197+ return _get_table_div (table , val );
198+ return val + 1 ;
199+ }
200+
201+ static unsigned long stm32_divider_get_rate (void __iomem * base ,
202+ struct clk_stm32_clock_data * data ,
203+ u16 div_id ,
204+ unsigned long parent_rate )
205+ {
206+ const struct stm32_div_cfg * divider = & data -> dividers [div_id ];
207+ unsigned int val ;
208+ unsigned int div ;
209+
210+ val = readl (base + divider -> offset ) >> divider -> shift ;
211+ val &= clk_div_mask (divider -> width );
212+ div = _get_div (divider -> table , val , divider -> flags , divider -> width );
213+
214+ if (!div ) {
215+ WARN (!(divider -> flags & CLK_DIVIDER_ALLOW_ZERO ),
216+ "%d: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n" ,
217+ div_id );
218+ return parent_rate ;
219+ }
220+
221+ return DIV_ROUND_UP_ULL ((u64 )parent_rate , div );
222+ }
223+
224+ static int stm32_divider_set_rate (void __iomem * base ,
225+ struct clk_stm32_clock_data * data ,
226+ u16 div_id , unsigned long rate ,
227+ unsigned long parent_rate )
228+ {
229+ const struct stm32_div_cfg * divider = & data -> dividers [div_id ];
230+ int value ;
231+ u32 val ;
232+
233+ value = divider_get_val (rate , parent_rate , divider -> table ,
234+ divider -> width , divider -> flags );
235+ if (value < 0 )
236+ return value ;
237+
238+ if (divider -> flags & CLK_DIVIDER_HIWORD_MASK ) {
239+ val = clk_div_mask (divider -> width ) << (divider -> shift + 16 );
240+ } else {
241+ val = readl (base + divider -> offset );
242+ val &= ~(clk_div_mask (divider -> width ) << divider -> shift );
243+ }
244+
245+ val |= (u32 )value << divider -> shift ;
246+
247+ writel (val , base + divider -> offset );
248+
249+ return 0 ;
250+ }
251+
178252static u8 clk_stm32_mux_get_parent (struct clk_hw * hw )
179253{
180254 struct clk_stm32_mux * mux = to_clk_stm32_mux (hw );
@@ -251,6 +325,70 @@ const struct clk_ops clk_stm32_gate_ops = {
251325 .disable_unused = clk_stm32_gate_disable_unused ,
252326};
253327
328+ static int clk_stm32_divider_set_rate (struct clk_hw * hw , unsigned long rate ,
329+ unsigned long parent_rate )
330+ {
331+ struct clk_stm32_div * div = to_clk_stm32_divider (hw );
332+ unsigned long flags = 0 ;
333+ int ret ;
334+
335+ if (div -> div_id == NO_STM32_DIV )
336+ return rate ;
337+
338+ spin_lock_irqsave (div -> lock , flags );
339+
340+ ret = stm32_divider_set_rate (div -> base , div -> clock_data , div -> div_id , rate , parent_rate );
341+
342+ spin_unlock_irqrestore (div -> lock , flags );
343+
344+ return ret ;
345+ }
346+
347+ static long clk_stm32_divider_round_rate (struct clk_hw * hw , unsigned long rate ,
348+ unsigned long * prate )
349+ {
350+ struct clk_stm32_div * div = to_clk_stm32_divider (hw );
351+ const struct stm32_div_cfg * divider ;
352+
353+ if (div -> div_id == NO_STM32_DIV )
354+ return rate ;
355+
356+ divider = & div -> clock_data -> dividers [div -> div_id ];
357+
358+ /* if read only, just return current value */
359+ if (divider -> flags & CLK_DIVIDER_READ_ONLY ) {
360+ u32 val ;
361+
362+ val = readl (div -> base + divider -> offset ) >> divider -> shift ;
363+ val &= clk_div_mask (divider -> width );
364+
365+ return divider_ro_round_rate (hw , rate , prate , divider -> table ,
366+ divider -> width , divider -> flags ,
367+ val );
368+ }
369+
370+ return divider_round_rate_parent (hw , clk_hw_get_parent (hw ),
371+ rate , prate , divider -> table ,
372+ divider -> width , divider -> flags );
373+ }
374+
375+ static unsigned long clk_stm32_divider_recalc_rate (struct clk_hw * hw ,
376+ unsigned long parent_rate )
377+ {
378+ struct clk_stm32_div * div = to_clk_stm32_divider (hw );
379+
380+ if (div -> div_id == NO_STM32_DIV )
381+ return parent_rate ;
382+
383+ return stm32_divider_get_rate (div -> base , div -> clock_data , div -> div_id , parent_rate );
384+ }
385+
386+ const struct clk_ops clk_stm32_divider_ops = {
387+ .recalc_rate = clk_stm32_divider_recalc_rate ,
388+ .round_rate = clk_stm32_divider_round_rate ,
389+ .set_rate = clk_stm32_divider_set_rate ,
390+ };
391+
254392struct clk_hw * clk_stm32_mux_register (struct device * dev ,
255393 const struct stm32_rcc_match_data * data ,
256394 void __iomem * base ,
@@ -292,3 +430,24 @@ struct clk_hw *clk_stm32_gate_register(struct device *dev,
292430
293431 return hw ;
294432}
433+
434+ struct clk_hw * clk_stm32_div_register (struct device * dev ,
435+ const struct stm32_rcc_match_data * data ,
436+ void __iomem * base ,
437+ spinlock_t * lock ,
438+ const struct clock_config * cfg )
439+ {
440+ struct clk_stm32_div * div = cfg -> clock_cfg ;
441+ struct clk_hw * hw = & div -> hw ;
442+ int err ;
443+
444+ div -> base = base ;
445+ div -> lock = lock ;
446+ div -> clock_data = data -> clock_data ;
447+
448+ err = clk_hw_register (dev , hw );
449+ if (err )
450+ return ERR_PTR (err );
451+
452+ return hw ;
453+ }
0 commit comments