brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · 084c71a Raw
235 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2020 Intel Corporation.4 *5 * Limitations:6 * - The hardware supports fixed period & configures only 2-wire mode.7 * - Supports normal polarity. Does not support changing polarity.8 * - When PWM is disabled, output of PWM will become 0(inactive). It doesn't9 *   keep track of running period.10 * - When duty cycle is changed, PWM output may be a mix of previous setting11 *   and new setting for the first period. From second period, the output is12 *   based on new setting.13 * - It is a dedicated PWM fan controller. There are no other consumers for14 *   this PWM controller.15 */16#include <linux/bitfield.h>17#include <linux/clk.h>18#include <linux/module.h>19#include <linux/platform_device.h>20#include <linux/mod_devicetable.h>21#include <linux/pwm.h>22#include <linux/regmap.h>23#include <linux/reset.h>24 25#define LGM_PWM_FAN_CON0		0x026#define LGM_PWM_FAN_EN_EN		BIT(0)27#define LGM_PWM_FAN_EN_DIS		0x028#define LGM_PWM_FAN_EN_MSK		BIT(0)29#define LGM_PWM_FAN_MODE_2WIRE		0x030#define LGM_PWM_FAN_MODE_MSK		BIT(1)31#define LGM_PWM_FAN_DC_MSK		GENMASK(23, 16)32 33#define LGM_PWM_FAN_CON1		0x434#define LGM_PWM_FAN_MAX_RPM_MSK		GENMASK(15, 0)35 36#define LGM_PWM_MAX_RPM			(BIT(16) - 1)37#define LGM_PWM_DEFAULT_RPM		400038#define LGM_PWM_MAX_DUTY_CYCLE		(BIT(8) - 1)39 40#define LGM_PWM_DC_BITS			841 42#define LGM_PWM_PERIOD_2WIRE_NS		(40 * NSEC_PER_MSEC)43 44struct lgm_pwm_chip {45	struct regmap *regmap;46	u32 period;47};48 49static inline struct lgm_pwm_chip *to_lgm_pwm_chip(struct pwm_chip *chip)50{51	return pwmchip_get_drvdata(chip);52}53 54static int lgm_pwm_enable(struct pwm_chip *chip, bool enable)55{56	struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip);57	struct regmap *regmap = pc->regmap;58 59	return regmap_update_bits(regmap, LGM_PWM_FAN_CON0, LGM_PWM_FAN_EN_MSK,60				  enable ? LGM_PWM_FAN_EN_EN : LGM_PWM_FAN_EN_DIS);61}62 63static int lgm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,64			 const struct pwm_state *state)65{66	struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip);67	u32 duty_cycle, val;68	int ret;69 70	/* The hardware only supports normal polarity and fixed period. */71	if (state->polarity != PWM_POLARITY_NORMAL || state->period < pc->period)72		return -EINVAL;73 74	if (!state->enabled)75		return lgm_pwm_enable(chip, 0);76 77	duty_cycle = min_t(u64, state->duty_cycle, pc->period);78	val = duty_cycle * LGM_PWM_MAX_DUTY_CYCLE / pc->period;79 80	ret = regmap_update_bits(pc->regmap, LGM_PWM_FAN_CON0, LGM_PWM_FAN_DC_MSK,81				 FIELD_PREP(LGM_PWM_FAN_DC_MSK, val));82	if (ret)83		return ret;84 85	return lgm_pwm_enable(chip, 1);86}87 88static int lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,89			     struct pwm_state *state)90{91	struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip);92	u32 duty, val;93 94	state->enabled = regmap_test_bits(pc->regmap, LGM_PWM_FAN_CON0,95					  LGM_PWM_FAN_EN_EN);96	state->polarity = PWM_POLARITY_NORMAL;97	state->period = pc->period; /* fixed period */98 99	regmap_read(pc->regmap, LGM_PWM_FAN_CON0, &val);100	duty = FIELD_GET(LGM_PWM_FAN_DC_MSK, val);101	state->duty_cycle = DIV_ROUND_UP(duty * pc->period, LGM_PWM_MAX_DUTY_CYCLE);102 103	return 0;104}105 106static const struct pwm_ops lgm_pwm_ops = {107	.get_state = lgm_pwm_get_state,108	.apply = lgm_pwm_apply,109};110 111static void lgm_pwm_init(struct lgm_pwm_chip *pc)112{113	struct regmap *regmap = pc->regmap;114	u32 con0_val;115 116	con0_val = FIELD_PREP(LGM_PWM_FAN_MODE_MSK, LGM_PWM_FAN_MODE_2WIRE);117	pc->period = LGM_PWM_PERIOD_2WIRE_NS;118	regmap_update_bits(regmap, LGM_PWM_FAN_CON1, LGM_PWM_FAN_MAX_RPM_MSK,119			   LGM_PWM_DEFAULT_RPM);120	regmap_update_bits(regmap, LGM_PWM_FAN_CON0, LGM_PWM_FAN_MODE_MSK,121			   con0_val);122}123 124static const struct regmap_config lgm_pwm_regmap_config = {125	.reg_bits = 32,126	.reg_stride = 4,127	.val_bits = 32,128};129 130static void lgm_clk_release(void *data)131{132	struct clk *clk = data;133 134	clk_disable_unprepare(clk);135}136 137static int lgm_clk_enable(struct device *dev, struct clk *clk)138{139	int ret;140 141	ret = clk_prepare_enable(clk);142	if (ret)143		return ret;144 145	return devm_add_action_or_reset(dev, lgm_clk_release, clk);146}147 148static void lgm_reset_control_release(void *data)149{150	struct reset_control *rst = data;151 152	reset_control_assert(rst);153}154 155static int lgm_reset_control_deassert(struct device *dev, struct reset_control *rst)156{157	int ret;158 159	ret = reset_control_deassert(rst);160	if (ret)161		return ret;162 163	return devm_add_action_or_reset(dev, lgm_reset_control_release, rst);164}165 166static int lgm_pwm_probe(struct platform_device *pdev)167{168	struct device *dev = &pdev->dev;169	struct reset_control *rst;170	struct pwm_chip *chip;171	struct lgm_pwm_chip *pc;172	void __iomem *io_base;173	struct clk *clk;174	int ret;175 176	chip = devm_pwmchip_alloc(dev, 1, sizeof(*pc));177	if (IS_ERR(chip))178		return PTR_ERR(chip);179	pc = to_lgm_pwm_chip(chip);180 181	io_base = devm_platform_ioremap_resource(pdev, 0);182	if (IS_ERR(io_base))183		return PTR_ERR(io_base);184 185	pc->regmap = devm_regmap_init_mmio(dev, io_base, &lgm_pwm_regmap_config);186	if (IS_ERR(pc->regmap))187		return dev_err_probe(dev, PTR_ERR(pc->regmap),188				     "failed to init register map\n");189 190	clk = devm_clk_get(dev, NULL);191	if (IS_ERR(clk))192		return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");193 194	ret = lgm_clk_enable(dev, clk);195	if (ret)196		return dev_err_probe(dev, ret, "failed to enable clock\n");197 198	rst = devm_reset_control_get_exclusive(dev, NULL);199	if (IS_ERR(rst))200		return dev_err_probe(dev, PTR_ERR(rst),201				     "failed to get reset control\n");202 203	ret = lgm_reset_control_deassert(dev, rst);204	if (ret)205		return dev_err_probe(dev, ret, "cannot deassert reset control\n");206 207	chip->ops = &lgm_pwm_ops;208 209	lgm_pwm_init(pc);210 211	ret = devm_pwmchip_add(dev, chip);212	if (ret < 0)213		return dev_err_probe(dev, ret, "failed to add PWM chip\n");214 215	return 0;216}217 218static const struct of_device_id lgm_pwm_of_match[] = {219	{ .compatible = "intel,lgm-pwm" },220	{ }221};222MODULE_DEVICE_TABLE(of, lgm_pwm_of_match);223 224static struct platform_driver lgm_pwm_driver = {225	.driver = {226		.name = "intel-pwm",227		.of_match_table = lgm_pwm_of_match,228	},229	.probe = lgm_pwm_probe,230};231module_platform_driver(lgm_pwm_driver);232 233MODULE_DESCRIPTION("Intel LGM Pulse Width Modulator driver");234MODULE_LICENSE("GPL v2");235