diff --git a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-common.dtsi b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-common.dtsi index 41cdf3bd6ce..ce91b0f632b 100644 --- a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-common.dtsi +++ b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-common.dtsi @@ -84,7 +84,7 @@ compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <128>; - simple-audio-card,name = "rockchip,hdmi"; + simple-audio-card,name = "rockchip,hdmi0"; status = "disabled"; simple-audio-card,cpu { @@ -123,7 +123,7 @@ }; rk809_sound: rk809-sound { - status = "okay"; + status = "disabled"; compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; simple-audio-card,name = "rockchip,rk809-codec"; @@ -133,7 +133,7 @@ sound-dai = <&i2s1_8ch>; }; simple-audio-card,codec { - sound-dai = <&rk809_codec 0>; + sound-dai = <&rk809_codec>; }; }; @@ -229,6 +229,19 @@ pinctrl-0 = <&vcc5v0_otg_en>; }; + simple_bat: battery { + compatible = "simple-battery"; + voltage-max-design-microvolt = <13000000>; + voltage-min-design-microvolt = <4500000>; + }; + + simple_vin: simple-vin { + compatible = "simple-adc-power-v1"; + io-channels = <&saradc 2>; + io-channel-names = "voltage"; + monitored-battery = <&simple_bat>; + }; + test-power { status = "okay"; }; @@ -562,7 +575,7 @@ }; rk809_codec: codec { - #sound-dai-cells = <1>; + #sound-dai-cells = <0>; compatible = "rockchip,rk809-codec", "rockchip,rk817-codec"; clocks = <&cru I2S1_MCLKOUT>; clock-names = "mclk"; @@ -573,7 +586,6 @@ pinctrl-0 = <&i2s1m0_mclk>; hp-volume = <20>; spk-volume = <3>; - mic-in-differential; status = "okay"; }; }; @@ -592,7 +604,7 @@ &i2s1_8ch { status = "disabled"; - rockchip,clk-trcm = <1>; + rockchip,trcm-sync-tx-only; pinctrl-names = "default"; pinctrl-0 = <&i2s1m0_sclktx &i2s1m0_lrcktx @@ -842,11 +854,11 @@ }; &u2phy0_otg { + phy-supply = <&vcc5v0_otg>; status = "okay"; }; &u2phy1_host { - phy-supply = <&vcc5v0_otg>; status = "okay"; }; diff --git a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-rev02.dts b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-rev02.dts index 6781337edcf..514cbc20b75 100644 --- a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-rev02.dts +++ b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-nanopi5-rev02.dts @@ -214,3 +214,8 @@ &sfc { status = "disabled"; }; + +&simple_bat { + voltage-max-design-microvolt = <5400000>; + voltage-min-design-microvolt = <4200000>; +}; diff --git a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-common.dtsi b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-common.dtsi index c3728f2e192..81e785c2e61 100644 --- a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-common.dtsi +++ b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-common.dtsi @@ -121,6 +121,19 @@ compatible = "pwm-backlight"; }; + simple_bat: battery { + compatible = "simple-battery"; + voltage-max-design-microvolt = <21000000>; + voltage-min-design-microvolt = <4500000>; + }; + + simple_vin: simple-vin { + compatible = "simple-adc-power-v2"; + io-channels = <&saradc 2>; + io-channel-names = "voltage"; + monitored-battery = <&simple_bat>; + }; + test-power { status = "okay"; }; @@ -157,6 +170,11 @@ mem-supply = <&vdd_cpu_big1_mem_s0>; }; +&display_subsystem { + clocks = <&hdptxphy_hdmi_clk0>, <&hdptxphy_hdmi_clk0>; + clock-names = "hdmi0_phy_pll", "hdmi1_phy_pll"; +}; + &gpu { mali-supply = <&vdd_gpu_s0>; mem-supply = <&vdd_gpu_mem_s0>; @@ -215,6 +233,10 @@ status = "okay"; }; +&hdptxphy_hdmi_clk0 { + status = "okay"; +}; + &hdptxphy_hdmi0 { status = "okay"; }; diff --git a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev01.dts b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev01.dts index 457098ca207..f75f10a77d0 100644 --- a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev01.dts +++ b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev01.dts @@ -73,11 +73,13 @@ }; fan: pwm-fan { - status = "disabled"; + status = "okay"; compatible = "pwm-fan"; #cooling-cells = <2>; + fan-supply = <&vcc5v0_sys>; pwms = <&pwm1 0 50000 0>; - cooling-levels = <0 50 100 150 200 255>; + cooling-levels = <0 45 70 110 160 255>; + rockchip,hold-time-ms = <2000>; rockchip,temp-trips = < 50000 1 55000 2 @@ -181,6 +183,11 @@ status = "okay"; }; +&display_subsystem { + clocks = <&hdptxphy_hdmi_clk0>, <&hdptxphy_hdmi_clk1>; + clock-names = "hdmi0_phy_pll", "hdmi1_phy_pll"; +}; + &dp0 { status = "okay"; }; @@ -263,6 +270,14 @@ pinctrl-0 = <&hdmim1_rx &hdmirx_det>; }; +&hdptxphy_hdmi_clk0 { + status = "okay"; +}; + +&hdptxphy_hdmi_clk1 { + status = "okay"; +}; + &hdptxphy_hdmi0 { status = "okay"; }; diff --git a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev08.dts b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev08.dts index 456745883f8..324fdc7f21d 100644 --- a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev08.dts +++ b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev08.dts @@ -131,6 +131,11 @@ status = "okay"; }; +&display_subsystem { + clocks = <&hdptxphy_hdmi_clk0>, <&hdptxphy_hdmi_clk1>; + clock-names = "hdmi0_phy_pll", "hdmi1_phy_pll"; +}; + &dp0 { status = "okay"; }; @@ -193,6 +198,14 @@ status = "okay"; }; +&hdptxphy_hdmi_clk0 { + status = "okay"; +}; + +&hdptxphy_hdmi_clk1 { + status = "okay"; +}; + &hdptxphy_hdmi0 { status = "okay"; }; diff --git a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev09.dts b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev09.dts index e2fc7c4180e..ea0a9a80771 100644 --- a/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev09.dts +++ b/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev09.dts @@ -72,11 +72,13 @@ }; fan: pwm-fan { - status = "disabled"; + status = "okay"; compatible = "pwm-fan"; #cooling-cells = <2>; + fan-supply = <&vcc5v0_sys>; pwms = <&pwm1 0 50000 0>; - cooling-levels = <0 50 100 150 200 255>; + cooling-levels = <0 45 70 110 160 255>; + rockchip,hold-time-ms = <2000>; rockchip,temp-trips = < 50000 1 55000 2 @@ -214,6 +216,11 @@ status = "okay"; }; +&display_subsystem { + clocks = <&hdptxphy_hdmi_clk0>, <&hdptxphy_hdmi_clk1>; + clock-names = "hdmi0_phy_pll", "hdmi1_phy_pll"; +}; + &dp0 { status = "okay"; }; @@ -296,6 +303,14 @@ pinctrl-0 = <&hdmim1_rx &hdmirx_det>; }; +&hdptxphy_hdmi_clk0 { + status = "okay"; +}; + +&hdptxphy_hdmi_clk1 { + status = "okay"; +}; + &hdptxphy_hdmi0 { status = "okay"; }; @@ -415,6 +430,7 @@ }; &i2c8 { + status = "okay"; pinctrl-0 = <&i2c8m2_xfer>; /* connected with Header_2.54MM */ }; diff --git a/kernel-5.10/drivers/hwmon/pwm-fan.c b/kernel-5.10/drivers/hwmon/pwm-fan.c index 6298da53ef1..381be156102 100644 --- a/kernel-5.10/drivers/hwmon/pwm-fan.c +++ b/kernel-5.10/drivers/hwmon/pwm-fan.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -23,20 +22,38 @@ #define MAX_PWM 255 +struct pwm_fan_tach { + int irq; + atomic_t pulses; + unsigned int rpm; + u8 pulses_per_revolution; +}; + +enum pwm_fan_enable_mode { + pwm_off_reg_off, + pwm_disable_reg_enable, + pwm_enable_reg_enable, + pwm_disable_reg_disable, +}; + struct thermal_trips { int temp; int state; }; struct pwm_fan_ctx { + struct device *dev; + struct mutex lock; struct pwm_device *pwm; + struct pwm_state pwm_state; struct regulator *reg_en; + enum pwm_fan_enable_mode enable_mode; + bool regulator_enabled; + bool enabled; - int irq; - atomic_t pulses; - unsigned int rpm; - u8 pulses_per_revolution; + int tach_count; + struct pwm_fan_tach *tachs; ktime_t sample_start; struct timer_list rpm_timer; @@ -48,14 +65,19 @@ struct pwm_fan_ctx { struct notifier_block thermal_nb; struct thermal_trips *thermal_trips; bool thermal_notifier_is_ok; + unsigned int delay_ms; + ktime_t time_in_state; + + struct hwmon_chip_info info; + struct hwmon_channel_info fan_channel; }; /* This handler assumes self resetting edge triggered interrupt. */ static irqreturn_t pulse_handler(int irq, void *dev_id) { - struct pwm_fan_ctx *ctx = dev_id; + struct pwm_fan_tach *tach = dev_id; - atomic_inc(&ctx->pulses); + atomic_inc(&tach->pulses); return IRQ_HANDLED; } @@ -64,13 +86,18 @@ static void sample_timer(struct timer_list *t) { struct pwm_fan_ctx *ctx = from_timer(ctx, t, rpm_timer); unsigned int delta = ktime_ms_delta(ktime_get(), ctx->sample_start); - int pulses; + int i; if (delta) { - pulses = atomic_read(&ctx->pulses); - atomic_sub(pulses, &ctx->pulses); - ctx->rpm = (unsigned int)(pulses * 1000 * 60) / - (ctx->pulses_per_revolution * delta); + for (i = 0; i < ctx->tach_count; i++) { + struct pwm_fan_tach *tach = &ctx->tachs[i]; + int pulses; + + pulses = atomic_read(&tach->pulses); + atomic_sub(pulses, &tach->pulses); + tach->rpm = (unsigned int)(pulses * 1000 * 60) / + (tach->pulses_per_revolution * delta); + } ctx->sample_start = ktime_get(); } @@ -78,26 +105,140 @@ static void sample_timer(struct timer_list *t) mod_timer(&ctx->rpm_timer, jiffies + HZ); } +static void pwm_fan_enable_mode_2_state(int enable_mode, + struct pwm_state *state, + bool *enable_regulator) +{ + switch (enable_mode) { + case pwm_disable_reg_enable: + /* disable pwm, keep regulator enabled */ + state->enabled = false; + *enable_regulator = true; + break; + case pwm_enable_reg_enable: + /* keep pwm and regulator enabled */ + state->enabled = true; + *enable_regulator = true; + break; + case pwm_off_reg_off: + case pwm_disable_reg_disable: + /* disable pwm and regulator */ + state->enabled = false; + *enable_regulator = false; + } +} + +static int pwm_fan_switch_power(struct pwm_fan_ctx *ctx, bool on) +{ + int ret = 0; + + if (!ctx->reg_en) + return ret; + + if (!ctx->regulator_enabled && on) { + ret = regulator_enable(ctx->reg_en); + if (ret == 0) + ctx->regulator_enabled = true; + } else if (ctx->regulator_enabled && !on) { + ret = regulator_disable(ctx->reg_en); + if (ret == 0) + ctx->regulator_enabled = false; + } + return ret; +} + +static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) +{ + struct pwm_state *state = &ctx->pwm_state; + int ret; + + if (ctx->enabled) + return 0; + + ret = pwm_fan_switch_power(ctx, true); + if (ret < 0) { + dev_err(ctx->dev, "failed to enable power supply\n"); + return ret; + } + + state->enabled = true; + ret = pwm_apply_state(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to enable PWM\n"); + goto disable_regulator; + } + + ctx->enabled = true; + + return 0; + +disable_regulator: + pwm_fan_switch_power(ctx, false); + return ret; +} + +static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) +{ + struct pwm_state *state = &ctx->pwm_state; + bool enable_regulator = false; + int ret; + + if (!ctx->enabled) + return 0; + + pwm_fan_enable_mode_2_state(ctx->enable_mode, + state, + &enable_regulator); + + state->enabled = false; + state->duty_cycle = 0; + ret = pwm_apply_state(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to disable PWM\n"); + return ret; + } + + pwm_fan_switch_power(ctx, enable_regulator); + + ctx->enabled = false; + + return 0; +} + static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) { + struct pwm_state *state = &ctx->pwm_state; unsigned long period; int ret = 0; - struct pwm_state state = { }; - mutex_lock(&ctx->lock); - if (ctx->pwm_value == pwm) - goto exit_set_pwm_err; + if (pwm > 0) { + if (ctx->enable_mode == pwm_off_reg_off) + /* pwm-fan hard disabled */ + return 0; - pwm_init_state(ctx->pwm, &state); - period = ctx->pwm->args.period; - state.duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); - state.enabled = pwm ? true : false; - - ret = pwm_apply_state(ctx->pwm, &state); + period = state->period; + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + ret = pwm_apply_state(ctx->pwm, state); + if (ret) + return ret; + ret = pwm_fan_power_on(ctx); + } else { + ret = pwm_fan_power_off(ctx); + } if (!ret) ctx->pwm_value = pwm; -exit_set_pwm_err: + + return ret; +} + +static int set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) +{ + int ret; + + mutex_lock(&ctx->lock); + ret = __set_pwm(ctx, pwm); mutex_unlock(&ctx->lock); + return ret; } @@ -112,70 +253,127 @@ static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm) ctx->pwm_fan_state = i; } -static ssize_t pwm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val) { - struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - unsigned long pwm; - int ret; + int ret = 0; + int old_val; - if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM) - return -EINVAL; + mutex_lock(&ctx->lock); - ret = __set_pwm(ctx, pwm); - if (ret) - return ret; + if (ctx->enable_mode == val) + goto out; - pwm_fan_update_state(ctx, pwm); - return count; -} + old_val = ctx->enable_mode; + ctx->enable_mode = val; -static ssize_t pwm_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + if (val == 0) { + /* Disable pwm-fan unconditionally */ + if (ctx->enabled) + ret = __set_pwm(ctx, 0); + else + ret = pwm_fan_switch_power(ctx, false); + if (ret) + ctx->enable_mode = old_val; + pwm_fan_update_state(ctx, 0); + } else { + /* + * Change PWM and/or regulator state if currently disabled + * Nothing to do if currently enabled + */ + if (!ctx->enabled) { + struct pwm_state *state = &ctx->pwm_state; + bool enable_regulator = false; + + state->duty_cycle = 0; + pwm_fan_enable_mode_2_state(val, + state, + &enable_regulator); + + pwm_apply_state(ctx->pwm, state); + pwm_fan_switch_power(ctx, enable_regulator); + pwm_fan_update_state(ctx, 0); + } + } +out: + mutex_unlock(&ctx->lock); - return sprintf(buf, "%u\n", ctx->pwm_value); + return ret; } -static ssize_t rpm_show(struct device *dev, - struct device_attribute *attr, char *buf) +static int pwm_fan_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + int ret; - return sprintf(buf, "%u\n", ctx->rpm); -} + switch (attr) { + case hwmon_pwm_input: + if (val < 0 || val > MAX_PWM) + return -EINVAL; + ret = set_pwm(ctx, val); + if (ret) + return ret; + pwm_fan_update_state(ctx, val); + break; + case hwmon_pwm_enable: + if (val < 0 || val > 3) + ret = -EINVAL; + else + ret = pwm_fan_update_enable(ctx, val); -static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); -static SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0); + return ret; + default: + return -EOPNOTSUPP; + } -static struct attribute *pwm_fan_attrs[] = { - &sensor_dev_attr_pwm1.dev_attr.attr, - &sensor_dev_attr_fan1_input.dev_attr.attr, - NULL, -}; + return 0; +} -static umode_t pwm_fan_attrs_visible(struct kobject *kobj, struct attribute *a, - int n) +static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) { - struct device *dev = container_of(kobj, struct device, kobj); struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - /* Hide fan_input in case no interrupt is available */ - if (n == 1 && ctx->irq <= 0) + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + *val = ctx->pwm_value; + return 0; + case hwmon_pwm_enable: + *val = ctx->enable_mode; + return 0; + } + return -EOPNOTSUPP; + case hwmon_fan: + *val = ctx->tachs[channel].rpm; return 0; - return a->mode; + default: + return -ENOTSUPP; + } } -static const struct attribute_group pwm_fan_group = { - .attrs = pwm_fan_attrs, - .is_visible = pwm_fan_attrs_visible, -}; +static umode_t pwm_fan_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_pwm: + return 0644; -static const struct attribute_group *pwm_fan_groups[] = { - &pwm_fan_group, - NULL, + case hwmon_fan: + return 0444; + + default: + return 0; + } +} + +static const struct hwmon_ops pwm_fan_hwmon_ops = { + .is_visible = pwm_fan_is_visible, + .read = pwm_fan_read, + .write = pwm_fan_write, }; /* thermal cooling device callbacks */ @@ -214,10 +412,14 @@ pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) if (!ctx || (state > ctx->pwm_fan_max_state)) return -EINVAL; + /* keep running after user request */ + if (ctx->delay_ms > 0) + ctx->time_in_state = ktime_add_ms(ktime_get(), ctx->delay_ms); + if (state == ctx->pwm_fan_state) return 0; - ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); + ret = set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); if (ret) { dev_err(&cdev->device, "Cannot set pwm!\n"); return ret; @@ -275,16 +477,14 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, return 0; } -static void pwm_fan_regulator_disable(void *data) -{ - regulator_disable(data); -} - -static void pwm_fan_pwm_disable(void *__ctx) +static void pwm_fan_cleanup(void *__ctx) { struct pwm_fan_ctx *ctx = __ctx; - pwm_disable(ctx->pwm); + del_timer_sync(&ctx->rpm_timer); + /* Switch off everything */ + ctx->enable_mode = pwm_disable_reg_disable; + pwm_fan_power_off(ctx); } static int pwm_fan_get_thermal_trips(struct device *dev, char *porp_name, @@ -354,7 +554,12 @@ static int pwm_fan_thermal_notifier_call(struct notifier_block *nb, if (state == ctx->pwm_fan_state) return NOTIFY_OK; - ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); + if (ktime_before(ktime_get(), ctx->time_in_state) && + state < ctx->pwm_fan_max_state) { + return NOTIFY_DONE; + } + + ret = set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); if (ret) return NOTIFY_BAD; @@ -382,8 +587,10 @@ static int pwm_fan_probe(struct platform_device *pdev) struct pwm_fan_ctx *ctx; struct device *hwmon; int ret; - struct pwm_state state = { }; - u32 ppr = 2; + const struct hwmon_channel_info **channels; + u32 *fan_channel_config; + int channel_count = 1; /* We always have a PWM channel. */ + int i; ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -391,81 +598,125 @@ static int pwm_fan_probe(struct platform_device *pdev) mutex_init(&ctx->lock); - ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL); + ctx->dev = &pdev->dev; + ctx->pwm = devm_pwm_get(dev, NULL); if (IS_ERR(ctx->pwm)) return dev_err_probe(dev, PTR_ERR(ctx->pwm), "Could not get PWM\n"); platform_set_drvdata(pdev, ctx); - ctx->irq = platform_get_irq_optional(pdev, 0); - if (ctx->irq == -EPROBE_DEFER) - return ctx->irq; - ctx->reg_en = devm_regulator_get_optional(dev, "fan"); if (IS_ERR(ctx->reg_en)) { if (PTR_ERR(ctx->reg_en) != -ENODEV) return PTR_ERR(ctx->reg_en); ctx->reg_en = NULL; - } else { - ret = regulator_enable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to enable fan supply: %d\n", ret); - return ret; - } - ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable, - ctx->reg_en); - if (ret) - return ret; } - ctx->pwm_value = MAX_PWM; + pwm_init_state(ctx->pwm, &ctx->pwm_state); - pwm_init_state(ctx->pwm, &state); /* - * __set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned + * set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned * long. Check this here to prevent the fan running at a too low * frequency. */ - if (state.period > ULONG_MAX / MAX_PWM + 1) { + if (ctx->pwm_state.period > ULONG_MAX / MAX_PWM + 1) { dev_err(dev, "Configured period too big\n"); return -EINVAL; } - /* Set duty cycle to maximum allowed and enable PWM output */ - state.duty_cycle = ctx->pwm->args.period - 1; - state.enabled = true; + ctx->enable_mode = pwm_disable_reg_enable; - ret = pwm_apply_state(ctx->pwm, &state); + /* + * Set duty cycle to maximum allowed and enable PWM output as well as + * the regulator. In case of error nothing is changed + */ + ret = set_pwm(ctx, MAX_PWM); if (ret) { dev_err(dev, "Failed to configure PWM: %d\n", ret); return ret; } timer_setup(&ctx->rpm_timer, sample_timer, 0); - ret = devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx); + ret = devm_add_action_or_reset(dev, pwm_fan_cleanup, ctx); if (ret) return ret; - of_property_read_u32(dev->of_node, "pulses-per-revolution", &ppr); - ctx->pulses_per_revolution = ppr; - if (!ctx->pulses_per_revolution) { - dev_err(dev, "pulses-per-revolution can't be zero.\n"); - return -EINVAL; + ctx->tach_count = platform_irq_count(pdev); + if (ctx->tach_count < 0) + return dev_err_probe(dev, ctx->tach_count, + "Could not get number of fan tachometer inputs\n"); + dev_dbg(dev, "%d fan tachometer inputs\n", ctx->tach_count); + + if (ctx->tach_count) { + channel_count++; /* We also have a FAN channel. */ + + ctx->tachs = devm_kcalloc(dev, ctx->tach_count, + sizeof(struct pwm_fan_tach), + GFP_KERNEL); + if (!ctx->tachs) + return -ENOMEM; + + ctx->fan_channel.type = hwmon_fan; + fan_channel_config = devm_kcalloc(dev, ctx->tach_count + 1, + sizeof(u32), GFP_KERNEL); + if (!fan_channel_config) + return -ENOMEM; + ctx->fan_channel.config = fan_channel_config; } - if (ctx->irq > 0) { - ret = devm_request_irq(dev, ctx->irq, pulse_handler, 0, - pdev->name, ctx); - if (ret) { - dev_err(dev, "Failed to request interrupt: %d\n", ret); - return ret; + channels = devm_kcalloc(dev, channel_count + 1, + sizeof(struct hwmon_channel_info *), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + channels[0] = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE); + + for (i = 0; i < ctx->tach_count; i++) { + struct pwm_fan_tach *tach = &ctx->tachs[i]; + u32 ppr = 2; + + tach->irq = platform_get_irq(pdev, i); + if (tach->irq == -EPROBE_DEFER) + return tach->irq; + if (tach->irq > 0) { + ret = devm_request_irq(dev, tach->irq, pulse_handler, 0, + pdev->name, tach); + if (ret) { + dev_err(dev, + "Failed to request interrupt: %d\n", + ret); + return ret; + } + } + + of_property_read_u32_index(dev->of_node, + "pulses-per-revolution", + i, + &ppr); + tach->pulses_per_revolution = ppr; + if (!tach->pulses_per_revolution) { + dev_err(dev, "pulses-per-revolution can't be zero.\n"); + return -EINVAL; } + + fan_channel_config[i] = HWMON_F_INPUT; + + dev_dbg(dev, "tach%d: irq=%d, pulses_per_revolution=%d\n", + i, tach->irq, tach->pulses_per_revolution); + } + + if (ctx->tach_count > 0) { ctx->sample_start = ktime_get(); mod_timer(&ctx->rpm_timer, jiffies + HZ); + + channels[1] = &ctx->fan_channel; } - hwmon = devm_hwmon_device_register_with_groups(dev, "pwmfan", - ctx, pwm_fan_groups); + ctx->info.ops = &pwm_fan_hwmon_ops; + ctx->info.info = channels; + + hwmon = devm_hwmon_device_register_with_info(dev, "pwmfan", + ctx, &ctx->info, NULL); if (IS_ERR(hwmon)) { dev_err(dev, "Failed to register hwmon device\n"); return PTR_ERR(hwmon); @@ -481,9 +732,12 @@ static int pwm_fan_probe(struct platform_device *pdev) ret = pwm_fan_register_thermal_notifier(dev, ctx); if (ret) dev_err(dev, "Failed to register thermal notifier: %d\n", ret); - else + else { + device_property_read_u32(dev, "rockchip,hold-time-ms", &ctx->delay_ms); + /* keep running at 1000ms on startup */ + ctx->time_in_state = ktime_add_ms(ktime_get(), ctx->delay_ms + 1000); ctx->thermal_notifier_is_ok = true; - return 0; + } } if (IS_ENABLED(CONFIG_THERMAL)) { cdev = devm_thermal_of_cooling_device_register(dev, @@ -496,78 +750,49 @@ static int pwm_fan_probe(struct platform_device *pdev) return ret; } ctx->cdev = cdev; - thermal_cdev_update(cdev); } return 0; } -static int pwm_fan_disable(struct device *dev) +static int pwm_fan_remove(struct platform_device *pdev) { - struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - struct pwm_args args; - int ret; + struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); - pwm_get_args(ctx->pwm, &args); - - if (ctx->pwm_value || ctx->thermal_notifier_is_ok) { - ret = pwm_config(ctx->pwm, 0, args.period); - if (ret < 0) - return ret; - - pwm_disable(ctx->pwm); + if (ctx->thermal_notifier_is_ok) { + ctx->thermal_notifier_is_ok = false; + rockchip_system_monitor_unregister_notifier(&ctx->thermal_nb); } - if (ctx->reg_en) { - ret = regulator_disable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to disable fan supply: %d\n", ret); - return ret; - } - } + pwm_fan_switch_power(ctx, false); return 0; } static void pwm_fan_shutdown(struct platform_device *pdev) { - pwm_fan_disable(&pdev->dev); + struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); + + pwm_fan_cleanup(ctx); } -#ifdef CONFIG_PM_SLEEP static int pwm_fan_suspend(struct device *dev) { - return pwm_fan_disable(dev); + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + + return pwm_fan_power_off(ctx); } static int pwm_fan_resume(struct device *dev) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - struct pwm_args pargs; - unsigned long duty; - int ret; - if (ctx->reg_en) { - ret = regulator_enable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to enable fan supply: %d\n", ret); - return ret; - } - } - - if (ctx->pwm_value == 0 && !ctx->thermal_notifier_is_ok) - return 0; - - pwm_get_args(ctx->pwm, &pargs); - duty = DIV_ROUND_UP_ULL(ctx->pwm_value * (pargs.period - 1), MAX_PWM); - ret = pwm_config(ctx->pwm, duty, pargs.period); - if (ret) - return ret; - return pwm_enable(ctx->pwm); + return set_pwm(ctx, ctx->pwm_value); } -#endif -static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); +static const struct dev_pm_ops pwm_fan_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pwm_fan_suspend, pwm_fan_resume) +}; static const struct of_device_id of_pwm_fan_match[] = { { .compatible = "pwm-fan", }, @@ -577,6 +802,7 @@ MODULE_DEVICE_TABLE(of, of_pwm_fan_match); static struct platform_driver pwm_fan_driver = { .probe = pwm_fan_probe, + .remove = pwm_fan_remove, .shutdown = pwm_fan_shutdown, .driver = { .name = "pwm-fan", diff --git a/kernel-5.10/drivers/media/usb/uvc/Kconfig b/kernel-5.10/drivers/media/usb/uvc/Kconfig index 4c2f4a3216f..2f853ad6186 100644 --- a/kernel-5.10/drivers/media/usb/uvc/Kconfig +++ b/kernel-5.10/drivers/media/usb/uvc/Kconfig @@ -19,3 +19,14 @@ config USB_VIDEO_CLASS_INPUT_EVDEV to report button events. If you are in doubt, say Y. + +config USB_VIDEO_CLASS_REALSENSE + bool "Workaround for Intel RealSense depth camera" + default n + depends on USB_VIDEO_CLASS + help + This option increases the UVC_URBS and UVC_MAX_STATUS_SIZE like + librealsense patches does. + + Link: https://github.com/IntelRealSense/librealsense + If you are in doubt, say N. diff --git a/kernel-5.10/drivers/media/usb/uvc/uvc_driver.c b/kernel-5.10/drivers/media/usb/uvc/uvc_driver.c index 34b1ca6e889..0c4c3ee9349 100644 --- a/kernel-5.10/drivers/media/usb/uvc/uvc_driver.c +++ b/kernel-5.10/drivers/media/usb/uvc/uvc_driver.c @@ -170,6 +170,11 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_Y12I, .fcc = V4L2_PIX_FMT_Y12I, }, + { + .name = "Greyscale 16 L/R (Y16I)", + .guid = UVC_GUID_FORMAT_Y16I, + .fcc = V4L2_PIX_FMT_Y16I, + }, { .name = "Depth data 16-bit (Z16)", .guid = UVC_GUID_FORMAT_Z16, @@ -225,6 +230,58 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_HEVC, .fcc = V4L2_PIX_FMT_HEVC, }, + { + .name = "Depth data 16-bit (D16)", + .guid = UVC_GUID_FORMAT_D16, + .fcc = V4L2_PIX_FMT_Z16, + }, + { + .name = "Packed raw data 10-bit", + .guid = UVC_GUID_FORMAT_W10, + .fcc = V4L2_PIX_FMT_W10, + }, + { + .name = "Confidence data (C )", + .guid = UVC_GUID_FORMAT_CONFIDENCE_MAP, + .fcc = V4L2_PIX_FMT_CONFIDENCE_MAP, + }, + /* FishEye 8-bit monochrome */ + { + .name = "Raw data 8-bit (RAW8)", + .guid = UVC_GUID_FORMAT_RAW8, + .fcc = V4L2_PIX_FMT_GREY, + }, + /* Legacy formats for backward-compatibility*/ + { + .name = "Raw data 16-bit (RW16)", + .guid = UVC_GUID_FORMAT_RW16, + .fcc = V4L2_PIX_FMT_RW16, + }, + { + .name = "16-bit Bayer BGBG/GRGR", + .guid = UVC_GUID_FORMAT_BAYER16, + .fcc = V4L2_PIX_FMT_SBGGR16, + }, + { + .name = "Z16 Huffman Compression", + .guid = UVC_GUID_FORMAT_Z16H, + .fcc = V4L2_PIX_FMT_Z16H, + }, + { + .name = "Frame Grabber (FG )", + .guid = UVC_GUID_FORMAT_FG, + .fcc = V4L2_PIX_FMT_FG, + }, + { + .name = "SR300 Depth/Confidence (INZC)", + .guid = UVC_GUID_FORMAT_INZC, + .fcc = V4L2_PIX_FMT_INZC, + }, + { + .name = "Relative IR (PAIR)", + .guid = UVC_GUID_FORMAT_PAIR, + .fcc = V4L2_PIX_FMT_PAIR, + }, }; /* ------------------------------------------------------------------------ @@ -3014,6 +3071,276 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel SR306 depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0aa3, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel SR300 depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0aa5, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D400/PSR depth camera*/ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0ad1, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D410/ASR depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0ad2, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D415/ASRC depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0ad3, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D430/AWG depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0ad4, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D450/AWGT depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0ad5, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* USB2 Descriptor, Depth Sensor */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0ad6, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D400 IMU Module */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0af2, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D420/PWG depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0af6, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D420_MM/PWGT depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0afe, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D410_MM/ASRT depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0aff, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D400_MM/PSRT depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b00, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D430_MM/AWGCT depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b01, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D460/DS5U depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b03, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D435/AWGC depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b07, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D405 S depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b0c, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel L500 depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b0d, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D435i depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b3a, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel L515 Pre-PRQ */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b3d, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel SR305 Depth Camera*/ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b48, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D416 Depth Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b49, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D430i depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b4b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D465 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b4d, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D405 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b5b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D455 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b5c, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel L515 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b64, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel L535 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b68, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D585 Depth Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b6a, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel S585 Safety Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b6b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, diff --git a/kernel-5.10/drivers/media/usb/uvc/uvcvideo.h b/kernel-5.10/drivers/media/usb/uvc/uvcvideo.h index 372de342807..66b25296e94 100644 --- a/kernel-5.10/drivers/media/usb/uvc/uvcvideo.h +++ b/kernel-5.10/drivers/media/usb/uvc/uvcvideo.h @@ -142,6 +142,9 @@ #define UVC_GUID_FORMAT_Y12I \ { 'Y', '1', '2', 'I', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y16I \ + { 'Y', '1', '6', 'I', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} #define UVC_GUID_FORMAT_Z16 \ { 'Z', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} @@ -172,6 +175,38 @@ { 'H', 'E', 'V', 'C', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_D16 \ + { 'P', 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_W10 \ + { 'W', '1', '0', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RAW8 \ + { 'R', 'A', 'W', '8', 0x66, 0x1a, 0x42, 0xa2, \ + 0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a} +#define UVC_GUID_FORMAT_CONFIDENCE_MAP \ + { 'C', ' ', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +/* Legacy formats */ +#define UVC_GUID_FORMAT_RW16 \ + { 'R', 'W', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BAYER16 \ + { 'R', 'W', '1', '6', 0x66, 0x1a, 0x42, 0xa2, \ + 0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a} +#define UVC_GUID_FORMAT_Z16H \ + { 'Z', '1', '6', 'H', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_FG \ + { 'F', 'G', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_INZC \ + { 'I', 'N', 'Z', 'C', 0x02, 0xb6, 0x0f, 0x48, \ + 0x97, 0x8c, 0xe4, 0xe8, 0x8a, 0xe8, 0x9b, 0x89} +#define UVC_GUID_FORMAT_PAIR \ + { 'P', 'A', 'I', 'R', 0x36, 0x85, 0x41, 0x48, \ + 0xb6, 0xbf, 0x8f, 0xc6, 0xff, 0xb0, 0x83, 0xa8} + /* ------------------------------------------------------------------------ * Driver specific constants. @@ -180,11 +215,19 @@ #define DRIVER_VERSION "1.1.1" /* Number of isochronous URBs. */ +#ifdef CONFIG_USB_VIDEO_CLASS_REALSENSE +#define UVC_URBS 16 +#else #define UVC_URBS 5 +#endif /* Maximum number of packets per URB. */ #define UVC_MAX_PACKETS 32 /* Maximum status buffer size in bytes of interrupt URB. */ +#ifdef CONFIG_USB_VIDEO_CLASS_REALSENSE +#define UVC_MAX_STATUS_SIZE 32 +#else #define UVC_MAX_STATUS_SIZE 16 +#endif #define UVC_CTRL_CONTROL_TIMEOUT 5000 #define UVC_CTRL_STREAMING_TIMEOUT 5000 diff --git a/kernel-5.10/drivers/media/v4l2-core/v4l2-ioctl.c b/kernel-5.10/drivers/media/v4l2-core/v4l2-ioctl.c index 2b94f62e71a..43ff80799d1 100644 --- a/kernel-5.10/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/kernel-5.10/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1314,6 +1314,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_Y10P: descr = "10-bit Greyscale (MIPI Packed)"; break; case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break; case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; + case V4L2_PIX_FMT_Y16I: descr = "Interleaved 16-bit Greyscale"; break; case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; case V4L2_PIX_FMT_INZI: descr = "Planar 10:16 Greyscale Depth"; break; case V4L2_PIX_FMT_CNF4: descr = "4-bit Depth Confidence (Packed)"; break; @@ -1431,6 +1432,14 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; + /* Librealsense formats*/ + case V4L2_PIX_FMT_RW16: descr = "16-bit Raw data"; break; + case V4L2_PIX_FMT_W10: descr = "10-bit packed 8888[2222]"; break; + case V4L2_PIX_FMT_CONFIDENCE_MAP: descr = "Packed [44] confidence data"; break; + case V4L2_PIX_FMT_FG: descr = "Frame Grabber (FG )"; break; + case V4L2_PIX_FMT_INZC: descr = "Planar Depth/Confidence (INZC)"; break; + case V4L2_PIX_FMT_PAIR: descr = "Relative IR (PAIR)"; break; + case V4L2_PIX_FMT_Z16H: descr = "Z16 Huffman Compression"; break; default: /* Compressed formats */ diff --git a/kernel-5.10/drivers/power/supply/Kconfig b/kernel-5.10/drivers/power/supply/Kconfig index 2d1539d25f1..6ed4bf972c8 100644 --- a/kernel-5.10/drivers/power/supply/Kconfig +++ b/kernel-5.10/drivers/power/supply/Kconfig @@ -870,4 +870,12 @@ config CHARGER_SGM41542 help Say Y to enable support for the SGM41542 battery charger. +config SIMPLE_ADC_POWER + tristate "Simple ADC power supply driver" + depends on IIO + default y if VENDOR_FRIENDLYELEC + help + Say Y here to enable support for the simple power supply driver + which uses IIO framework to read adc. + endif # POWER_SUPPLY diff --git a/kernel-5.10/drivers/power/supply/Makefile b/kernel-5.10/drivers/power/supply/Makefile index 4d1d8cbaf1c..6739e2d4b59 100644 --- a/kernel-5.10/drivers/power/supply/Makefile +++ b/kernel-5.10/drivers/power/supply/Makefile @@ -8,6 +8,7 @@ power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o obj-$(CONFIG_POWER_SUPPLY) += power_supply.o obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o +obj-$(CONFIG_SIMPLE_ADC_POWER) += simple_adc_power.o obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_APM_POWER) += apm_power.o diff --git a/kernel-5.10/drivers/power/supply/simple_adc_power.c b/kernel-5.10/drivers/power/supply/simple_adc_power.c new file mode 100644 index 00000000000..b7bbbd04127 --- /dev/null +++ b/kernel-5.10/drivers/power/supply/simple_adc_power.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Simple ADC power supply driver + * + * Copyright (c) 2024 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyelec.com) + * + * based on ingenic-battery.c + */ + +#include +#include +#include +#include +#include +#include + +struct sadc_power_priv { + struct device *dev; + struct iio_channel *iio_v; + struct power_supply_desc desc; + struct power_supply *psy; + struct power_supply_battery_info info; + const struct sadc_platform_data *pdata; + int online; +}; + +struct sadc_platform_data { + int (*to_voltage)(int raw); +}; + +static int sadc_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sadc_power_priv *priv = power_supply_get_drvdata(psy); + struct power_supply_battery_info *info = &priv->info; + int raw = 0; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_HEALTH: + ret = iio_read_channel_raw(priv->iio_v, &raw); + val->intval = priv->pdata->to_voltage(raw); + if (val->intval < info->voltage_min_design_uv) + val->intval = POWER_SUPPLY_HEALTH_DEAD; + else if (val->intval > info->voltage_max_design_uv) + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + else + val->intval = POWER_SUPPLY_HEALTH_GOOD; + return ret < 0 ? ret : 0; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = priv->online; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = iio_read_channel_raw(priv->iio_v, &raw); + val->intval = priv->pdata->to_voltage(raw); + return ret < 0 ? ret : 0; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = info->voltage_min_design_uv; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = info->voltage_max_design_uv; + return 0; + default: + return -EINVAL; + } +} + +static enum power_supply_property sadc_power_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, +}; + +static int sadc_to_voltage_v1(int raw) { + int mv = 5000; + + if (raw > 160 && raw < 1024) { + mv = raw * 196 - 2130; + mv /= 10; + } + + return (mv * 1000); +} + +static int sadc_to_voltage_v2(int raw) { + int mv = raw * 2475 / 512; + + return (mv * 1000); +} + +static const struct sadc_platform_data sadc_pdata_v1 = { + .to_voltage = sadc_to_voltage_v1, +}; + +static const struct sadc_platform_data sadc_pdata_v2 = { + .to_voltage = sadc_to_voltage_v2, +}; + +static const struct of_device_id sadc_power_of_match[] = { + { .compatible = "simple-adc-power-v1", .data = &sadc_pdata_v1 }, + { .compatible = "simple-adc-power-v2", .data = &sadc_pdata_v2 }, + { }, +}; +MODULE_DEVICE_TABLE(of, sadc_power_of_match); + +static int sadc_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *match; + struct sadc_power_priv *priv; + struct power_supply_config psy_cfg = {}; + struct power_supply_desc *desc; + int ret; + + match = of_match_device(sadc_power_of_match, dev); + if (!match || !match->data) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->online = 1; + priv->pdata = match->data; + + priv->iio_v = devm_iio_channel_get(dev, "voltage"); + if (IS_ERR(priv->iio_v)) + return PTR_ERR(priv->iio_v); + + desc = &priv->desc; + desc->name = dev_name(dev); + desc->type = POWER_SUPPLY_TYPE_MAINS; + desc->properties = sadc_power_properties; + desc->num_properties = ARRAY_SIZE(sadc_power_properties); + desc->get_property = sadc_power_get_property; + + psy_cfg.drv_data = priv; + psy_cfg.of_node = dev->of_node; + + priv->psy = devm_power_supply_register(dev, desc, &psy_cfg); + if (IS_ERR(priv->psy)) + return dev_err_probe(dev, PTR_ERR(priv->psy), + "Unable to register supply\n"); + + ret = power_supply_get_battery_info(priv->psy, &priv->info); + if (ret) { + dev_err(dev, "Unable to get battery info: %d\n", ret); + return ret; + } + if (priv->info.voltage_min_design_uv < 0) { + dev_err(dev, "Unable to get voltage min design\n"); + return priv->info.voltage_min_design_uv; + } + if (priv->info.voltage_max_design_uv < 0) { + dev_err(dev, "Unable to get voltage max design\n"); + return priv->info.voltage_max_design_uv; + } + + return 0; +} + +static struct platform_driver sadc_power_driver = { + .driver = { + .name = "simple-adc-power", + .of_match_table = of_match_ptr(sadc_power_of_match), + }, + .probe = sadc_power_probe, +}; +module_platform_driver(sadc_power_driver); + +MODULE_ALIAS("platform:simple-adc-power"); +MODULE_AUTHOR("support@friendlyarm.com"); +MODULE_DESCRIPTION("Simple ADC power supply driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel-5.10/drivers/power/supply/test_power.c b/kernel-5.10/drivers/power/supply/test_power.c index adac25e9a61..f86b66d53da 100644 --- a/kernel-5.10/drivers/power/supply/test_power.c +++ b/kernel-5.10/drivers/power/supply/test_power.c @@ -28,7 +28,7 @@ enum test_power_id { static int ac_online = 1; static int usb_online = 1; -static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; +static int battery_status = POWER_SUPPLY_STATUS_FULL; static int battery_health = POWER_SUPPLY_HEALTH_GOOD; static int battery_present = 1; /* true */ static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; diff --git a/kernel-5.10/include/soc/rockchip/rockchip_dmc.h b/kernel-5.10/include/soc/rockchip/rockchip_dmc.h index 634f5f3f359..e3cc9306f71 100644 --- a/kernel-5.10/include/soc/rockchip/rockchip_dmc.h +++ b/kernel-5.10/include/soc/rockchip/rockchip_dmc.h @@ -118,7 +118,7 @@ rockchip_dmcfreq_vop_bandwidth_init(struct dmcfreq_common_info *info) { } -bool inline int rockchip_dmcfreq_vop_bandwidth_avail(void) +static inline bool rockchip_dmcfreq_vop_bandwidth_avail(void) { return false; } diff --git a/kernel-5.10/include/uapi/linux/videodev2.h b/kernel-5.10/include/uapi/linux/videodev2.h index 514db71fb83..a9380872a2a 100644 --- a/kernel-5.10/include/uapi/linux/videodev2.h +++ b/kernel-5.10/include/uapi/linux/videodev2.h @@ -736,11 +736,20 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */ #define V4L2_PIX_FMT_Y8I v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */ #define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */ +#define V4L2_PIX_FMT_Y16I v4l2_fourcc('Y', '1', '6', 'I') /* Greyscale 16-bit L/R interleaved */ #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ +/* Librealsense development */ +#define V4L2_PIX_FMT_RW16 v4l2_fourcc('R', 'W', '1', '6') /* Raw data 16-bit */ +#define V4L2_PIX_FMT_W10 v4l2_fourcc('W', '1', '0', ' ') /* Packed raw data 10-bit */ +#define V4L2_PIX_FMT_CONFIDENCE_MAP v4l2_fourcc('C', ' ', ' ', ' ') /* Two pixels in one byte */ +#define V4L2_PIX_FMT_FG v4l2_fourcc('F', 'G', ' ', ' ') /* Frame Grabber */ +#define V4L2_PIX_FMT_INZC v4l2_fourcc('I', 'N', 'Z', 'C') /* Planar Depth/Confidence */ +#define V4L2_PIX_FMT_PAIR v4l2_fourcc('P', 'A', 'I', 'R') /* Relative IR */ +#define V4L2_PIX_FMT_Z16H v4l2_fourcc('Z', '1', '6', 'H') /* Depth Z16 custom Huffman Code compression*/ /* 10bit raw bayer packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */