if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- val = readl(divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
+ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
+ val = div_mask(divider) << (divider->shift + 16);
+ } else {
+ val = readl(divider->reg);
+ val &= ~(div_mask(divider) << divider->shift);
+ }
val |= value << divider->shift;
writel(val, divider->reg);
struct clk *clk;
struct clk_init_data init;
+ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+ if (width + shift > 16) {
+ pr_warn("divider value exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
/* allocate the divider */
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
if (!div) {
* Some hardware implementations gracefully handle this case and allow a
* zero divisor by not modifying their input clock
* (divide by one / bypass).
+ * CLK_DIVIDER_HIWORD_MASK - The divider settings are only in lower 16-bit
+ * of this register, and mask of divider bits are in higher 16-bit of this
+ * register. While setting the divider bits, higher 16-bit should also be
+ * updated to indicate changing divider bits.
*/
struct clk_divider {
struct clk_hw hw;
#define CLK_DIVIDER_ONE_BASED BIT(0)
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
+#define CLK_DIVIDER_HIWORD_MASK BIT(3)
extern const struct clk_ops clk_divider_ops;
struct clk *clk_register_divider(struct device *dev, const char *name,