drivers/pwm/pwm-ntxec.c
Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-ntxec.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pwm/pwm-ntxec.c- Extension
.c- Size
- 4960 bytes
- Lines
- 166
- Domain
- Driver Families
- Bucket
- drivers/pwm
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/mfd/ntxec.hlinux/module.hlinux/platform_device.hlinux/pwm.hlinux/regmap.hlinux/types.h
Detected Declarations
struct ntxec_pwmfunction valuefunction ntxec_pwm_applyfunction ntxec_pwm_probe
Annotated Snippet
struct ntxec_pwm {
struct ntxec *ec;
};
static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip)
{
return pwmchip_get_drvdata(chip);
}
#define NTXEC_REG_AUTO_OFF_HI 0xa1
#define NTXEC_REG_AUTO_OFF_LO 0xa2
#define NTXEC_REG_ENABLE 0xa3
#define NTXEC_REG_PERIOD_LOW 0xa4
#define NTXEC_REG_PERIOD_HIGH 0xa5
#define NTXEC_REG_DUTY_LOW 0xa6
#define NTXEC_REG_DUTY_HIGH 0xa7
/*
* The time base used in the EC is 8MHz, or 125ns. Period and duty cycle are
* measured in this unit.
*/
#define TIME_BASE_NS 125
/*
* The maximum input value (in nanoseconds) is determined by the time base and
* the range of the hardware registers that hold the converted value.
* It fits into 32 bits, so we can do our calculations in 32 bits as well.
*/
#define MAX_PERIOD_NS (TIME_BASE_NS * 0xffff)
static int ntxec_pwm_set_raw_period_and_duty_cycle(struct pwm_chip *chip,
int period, int duty)
{
struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
/*
* Changes to the period and duty cycle take effect as soon as the
* corresponding low byte is written, so the hardware may be configured
* to an inconsistent state after the period is written and before the
* duty cycle is fully written. If, in such a case, the old duty cycle
* is longer than the new period, the EC may output 100% for a moment.
*
* To minimize the time between the changes to period and duty cycle
* taking effect, the writes are interleaved.
*/
struct reg_sequence regs[] = {
{ NTXEC_REG_PERIOD_HIGH, ntxec_reg8(period >> 8) },
{ NTXEC_REG_DUTY_HIGH, ntxec_reg8(duty >> 8) },
{ NTXEC_REG_PERIOD_LOW, ntxec_reg8(period) },
{ NTXEC_REG_DUTY_LOW, ntxec_reg8(duty) },
};
return regmap_multi_reg_write(priv->ec->regmap, regs, ARRAY_SIZE(regs));
}
static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev,
const struct pwm_state *state)
{
struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
unsigned int period, duty;
int res;
if (state->polarity != PWM_POLARITY_NORMAL)
return -EINVAL;
period = min_t(u64, state->period, MAX_PERIOD_NS);
duty = min_t(u64, state->duty_cycle, period);
period /= TIME_BASE_NS;
duty /= TIME_BASE_NS;
/*
* Writing a duty cycle of zero puts the device into a state where
* writing a higher duty cycle doesn't result in the brightness that it
* usually results in. This can be fixed by cycling the ENABLE register.
*
* As a workaround, write ENABLE=0 when the duty cycle is zero.
* The case that something has previously set the duty cycle to zero
* but ENABLE=1, is not handled.
*/
if (state->enabled && duty != 0) {
res = ntxec_pwm_set_raw_period_and_duty_cycle(chip, period, duty);
if (res)
return res;
res = regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(1));
if (res)
return res;
Annotation
- Immediate include surface: `linux/mfd/ntxec.h`, `linux/module.h`, `linux/platform_device.h`, `linux/pwm.h`, `linux/regmap.h`, `linux/types.h`.
- Detected declarations: `struct ntxec_pwm`, `function value`, `function ntxec_pwm_apply`, `function ntxec_pwm_probe`.
- Atlas domain: Driver Families / drivers/pwm.
- Implementation status: source implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.