Keywords covered in this lecture
clk prepare unprepare gating
gpio-gate-clock device tree
sleepable clock enable disable
free linux kernel development course
free linux device drivers course
The gate clock case study assumed something that does not always hold: that the
gate register is plain MMIO. Plenty of real gate clocks live behind a discrete chip on
I2C or SPI instead, and a linux i2c spi gate clock cannot use
struct clk_gate or clk_hw_register_gate() at all. This
lecture covers the workaround the CCF itself relies on, plus a DT-only gate clock type
that needs neither MMIO nor a discrete chip.
What You Will Learn
- Why struct clk_gate and clk_hw_register_gate() cannot be used for I2C/SPI gate chips
- Why prepare/unprepare, not enable/disable, is the correct home for sleepable gating logic
- The consumer-side contract that guarantees this workaround always works correctly
- Writing an original I2C-based gate clock using prepare/unprepare
- The DT-only gpio-gate-clock compatible that needs no driver at all
Prerequisites
- Gate clock driver case study (previous lecture)
- CCF clk_ops callback reference guide (sleep-capable vs atomic-only rule)
- Fixed and PWM clock bindings (DT-only clock pattern)
Why struct clk_gate Does Not Work for I2C/SPI Chips
Two separate assumptions baked into last lecture’s gate clock quietly break once the
hardware sits behind I2C or SPI instead of MMIO:
- struct clk_gate stores an __iomem register pointer, which is meaningless for a discrete bus-attached chip
- clk_gate_ops’s .enable/.disable are called with a spinlock held and must never sleep, but I2C/SPI register accesses always can sleep
Both problems have the same solution, and it is one this course already previewed
back in the clk_ops callback reference lecture.
The Workaround: Gate Through prepare/unprepare Instead
Since prepare/unprepare/is_prepared are
explicitly allowed to sleep, moving your gating logic into those callbacks instead of
enable/disable resolves both problems at once: no MMIO
register is assumed, and sleeping I2C/SPI transactions are safe to perform.
This is guaranteed to behave correctly because of a rule on the consumer side that
this course covered early in this chapter: every consumer must call
clk_prepare() before clk_enable(), and must follow
clk_disable() with clk_unprepare(). That ordering means:
Because clk_enable() is always preceded by clk_prepare(),
and your .prepare callback already turned the clock on by that point, your
.enable callback (if you provide one at all) can simply do nothing and
return success. The same logic applies in reverse for
clk_disable()/clk_unprepare() and your
.unprepare callback.
Original Demo: An I2C-Based Gate Clock
/* ep_i2c_gate_clk.c - gating logic lives in prepare/unprepare, since I2C access may sleep */
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#define EP_GATE_CTRL_REG 0x10
#define EP_GATE_ENABLE_BIT BIT(0)
struct ep_i2c_gate_clk {
struct clk_hw hw;
struct i2c_client *client;
bool prepared;
};
static inline struct ep_i2c_gate_clk *to_ep_i2c_gate(struct clk_hw *hw)
{
return container_of(hw, struct ep_i2c_gate_clk, hw);
}
static int ep_i2c_gate_prepare(struct clk_hw *hw)
{
struct ep_i2c_gate_clk *gate = to_ep_i2c_gate(hw);
int ret;
/* i2c_smbus_write_byte_data() may sleep - safe here, unsafe in .enable */
ret = i2c_smbus_write_byte_data(gate->client, EP_GATE_CTRL_REG,
EP_GATE_ENABLE_BIT);
if (ret)
return ret;
gate->prepared = true;
return 0;
}
static void ep_i2c_gate_unprepare(struct clk_hw *hw)
{
struct ep_i2c_gate_clk *gate = to_ep_i2c_gate(hw);
i2c_smbus_write_byte_data(gate->client, EP_GATE_CTRL_REG, 0);
gate->prepared = false;
}
static int ep_i2c_gate_is_prepared(struct clk_hw *hw)
{
return to_ep_i2c_gate(hw)->prepared;
}
static const struct clk_ops ep_i2c_gate_ops = {
.prepare = ep_i2c_gate_prepare,
.unprepare = ep_i2c_gate_unprepare,
.is_prepared = ep_i2c_gate_is_prepared,
/* no .enable/.disable at all - gating fully happens in prepare/unprepare */
};
static int ep_i2c_gate_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ep_i2c_gate_clk *gate;
struct clk_init_data init = {};
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
if (!gate)
return -ENOMEM;
gate->client = client;
init.name = "ep_i2c_gate_clk";
init.ops = &ep_i2c_gate_ops;
init.flags = 0;
gate->hw.init = &init;
return devm_clk_hw_register(dev, &gate->hw);
}
static const struct of_device_id ep_i2c_gate_of_match[] = {
{ .compatible = "ep,clk-i2c-gate-demo" },
{ }
};
MODULE_DEVICE_TABLE(of, ep_i2c_gate_of_match);
static struct i2c_driver ep_i2c_gate_driver = {
.probe = ep_i2c_gate_probe,
.driver = {
.name = "ep_clk_i2c_gate_demo",
.of_match_table = ep_i2c_gate_of_match,
},
};
module_i2c_driver(ep_i2c_gate_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala I2C gate clock demo");
Notice this driver uses the low-level clk_hw_register() interface
directly rather than a type-specific helper, exactly the pattern from the registration
styles lecture earlier in this chapter — there is no dedicated
clk_hw_register_i2c_gate() helper, since I2C/SPI gate chips vary too much
from one another for a single generic helper to cover.
The gpio-gate-clock DT-Only Alternative
A third option exists for the simplest case of all: a clock gated purely by toggling
a GPIO line, with no register interface of any kind, MMIO or otherwise. Like
fixed-clock and pwm-clock from an earlier lecture, this is a
DT-only compatible string already handled by an existing in-tree driver, requiring no
code from you.
ep_gpio_gated_clk: ep-gpio-gated-clk {
compatible = "gpio-gate-clock";
#clock-cells = <0>;
clocks = <&ep_ext_osc>;
enable-gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>;
};
/* consumer */
ep_wifi_module: wifi@0 {
compatible = "ep,fake-wifi-module";
reg = <0>;
clocks = <&ep_gpio_gated_clk>;
};
The required properties are compatible = "gpio-gate-clock",
#clock-cells = <0>, and enable-gpios; an optional
clocks property can name a single upstream parent, and up to one parent is
supported. Under the hood, an existing kernel driver toggles the GPIO line whenever the
clock is enabled or disabled — you only describe the wiring in the device tree.
Three Ways to Gate a Clock
| Approach | Control Path | Driver Code Needed? |
|---|---|---|
| struct clk_gate + clk_hw_register_gate() | MMIO register bit | Yes, a probe function |
| Custom clk_ops with prepare/unprepare | Sleepable I2C/SPI transaction | Yes, a probe function |
| compatible = “gpio-gate-clock” | GPIO line toggle | None |
Common Mistakes
- Putting an I2C/SPI register write inside .enable instead of .prepare
- Trying to reuse struct clk_gate for a discrete bus-attached gate chip
- Writing a driver for a simple GPIO-only gate when gpio-gate-clock already covers it
- Assuming .enable/.disable are still called even when .prepare/.unprepare already did the gating
Best Practices
- Move all sleepable bus transactions into prepare/unprepare, never enable/disable
- Track prepared state explicitly so is_prepared can answer without touching the bus
- Use gpio-gate-clock for the simplest GPIO-only case before writing any driver
- Document clearly why enable/disable are absent when gating is done in prepare/unprepare
Summary and Key Takeaways
- struct clk_gate and clk_hw_register_gate() assume MMIO and cannot be reused for I2C/SPI chips
- Moving gating logic into prepare/unprepare is safe because of the guaranteed clk_prepare→clk_enable ordering
- There is no generic registration helper for I2C/SPI gate clocks; use plain clk_hw_register()
- gpio-gate-clock handles the simplest GPIO-only gating case with zero driver code
Frequently Asked Questions
Why can’t I2C/SPI gate chips just implement .enable/.disable?
Because those callbacks are called with a spinlock held and must never sleep, while
I2C and SPI register accesses always can sleep.
Is it safe to leave .enable/.disable unimplemented if gating happens in prepare/unprepare?
Yes, because every consumer is required to call clk_prepare() before clk_enable()
and clk_unprepare() after clk_disable(), so the gating has already happened by the
time enable/disable would run.
Is there a dedicated registration helper for I2C/SPI gate clocks?
No, there is no generic helper since these chips vary too much; use the low-level
clk_hw_register() interface with your own custom clk_ops instead.
Can gpio-gate-clock have a parent clock?
Yes, an optional clocks property names a single upstream parent; a maximum of one
parent is supported.
Does gpio-gate-clock support changing the clock’s rate?
No, it only toggles the GPIO line to gate the clock on or off; any rate behavior
comes entirely from its optional parent clock.
Suggested Images For This Lecture
- Diagram: clk_prepare/clk_enable ordering making prepare-based gating safe
- Diagram: I2C gate clock writing a control register over a sleepable bus
- Diagram: gpio-gate-clock toggling a GPIO line with no driver code involved
Continue This Free Linux Kernel Development Course
Next, we move to the multiplexer clock case study and implement set_parent/get_parent
for a clock with multiple possible inputs.
