Merge commit 'cbb33e40aadf1f6a766ba3d63121c7b766a9f2f4'

* commit 'cbb33e40aadf1f6a766ba3d63121c7b766a9f2f4':
  drm/rockchip: vop2: Ensure rk3576 sharp/post-scaler/split are mutually exclusive
  arm64: dts: rockchip: rk3528: Add iommu shared bitmask for avsd and vdpu
  video: rockchip: mpp: fix share iommu issue for rk3528 on Arch32
  Revert "power: add universal charger driver support"
  iio: adc: rockchip_saradc: fix crash cause by saradc
  iio: adc: rockchip_saradc: fix the variable naming conflict
  drm/bridge: analogix_dp: add support for ASSR mode
  UPSTREAM: phy: Add Embedded DisplayPort and DisplayPort submodes
  video: rockchip: rga3: enable scale/FBC-in error intr
  video: rockchip: rga3: fix boundary protection for RGA2 average
  drm/rockchip: dsi2: update for dsi timing limit
  Revert "misc: add gpio-detection driver"
  Revert "power: charger: add new sy6982c/sy6982e driver"
  video: rockchip: dvbm: sync code from 5.10
  Revert "power: add ec battery driver"
  Revert "misc: add usb camera pd pin control driver"

Change-Id: I7273c1f3b840906a1ed9c5a6fb38e130775236e9
This commit is contained in:
Tao Huang
2025-02-10 20:23:12 +08:00
33 changed files with 368 additions and 2797 deletions

View File

@@ -1,37 +0,0 @@
Required properties:
- compatible: should be "gpio-detection"
- status:
- pinctrl-0 : phandle referencing pin configuration of the gpio controller
- pinctrl-names : a pinctrl state named "default" must be defined
- car-reverse : a describtion to show the gpio will be use to car reverse
- car-acc : a describtion to show the gpio will be use to car accelerate
- gpios : The GPIO to set high/low, see "gpios property" in
Documentation/devicetree/bindings/gpio/gpio.txt. If the pin should be
low to power down the board set it to "Active Low", otherwise set
gpio to "Active High".
- linux,debounce-ms: interrupt debounce time. (u32)
- label : The label / name for this partition. If omitted, the label is taken
- gpio,wakeup : To enable the wakeup comparator in probe
Example:
gpio_det: gpio-det {
compatible = "gpio-detection";
status = "okay";
pinctrl-0 = <&gpio3_b1 &gpio3_b2>;
pinctrl-names = "default";
car-reverse {
car-reverse-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
linux,debounce-ms = <5>;
label = "car-reverse";
gpio,wakeup;
};
car-acc {
car-acc-gpios = <&gpio3 9 GPIO_ACTIVE_HIGH>;
linux,debounce-ms = <5>;
label = "car-acc";
gpio,wakeup;
};
};

View File

@@ -1,16 +0,0 @@
* Rockchip USB camera GPIO control driver
Required properties:
- compatible: should be "usb-cam-gpio"
- hd-cam-pin: HD camera on gpio pin
- ir-cam-pin: IR camera on gpio pin
Example:
usb_cam_gpio: usb-cam-gpio {
compatible = "usb-cam-gpio";
pinctrl-names = "default";
pinctrl-0 = <&usb_cam_on_gpio>;
hd-cam-pin = <&gpio3 GPIO_A1 GPIO_ACTIVE_LOW>;
ir-cam-pin = <&gpio3 GPIO_A2 GPIO_ACTIVE_HIGH>;
status = "okay";
};

View File

@@ -1,20 +0,0 @@
Binding for EC Battery
Required properties:
- compatible: Should contain one of the following:
* "rockchip,ec-battery"
- reg: integer, smbus address of the device.
- tvirtual_power: integer, test power, if battery is not exist;
- monitor_sec: integer, delay time of queue_delayed_work (s);
Optional properties:
Example:
ec_battery: ec_battery09 {
compatible = "rockchip,ec-battery";
reg = <0x76>;
virtual_power = <0>;
monitor_sec = <5>;
};

View File

@@ -1,14 +0,0 @@
Binding for sy6982c Charger
Required properties:
- compatible: Should contain one of the following:
* "sy6982c-charger"
- extcon: extcon specifier for the Charger.
Example:
sy6982c {
status = "okay";
compatible = "sy6982c-charger";
extcon = <&u2phy0>;
};

View File

@@ -1,16 +0,0 @@
Binding for UNIVERSAL Charger
Required properties:
- compatible: Should contain one of the following:
* "universal-charger"
- extcon: extcon specifier for the Charger.
- dc-det-gpio: gpio for dc detect.
Example:
universal_charger {
status = "okay";
compatible = "universal-charger";
extcon = <&u2phy0>;
dc-det-gpio = <&gpio3 1 GPIO_ACTIVE_HIGH>;
};

View File

@@ -452,6 +452,7 @@
compatible = "rockchip,mpp-service";
rockchip,taskqueue-count = <5>;
rockchip,resetgroup-count = <5>;
rockchip,iommu-shared-mask = <0xa>; /* 0x2: avsd, 0x8: vdpu */
status = "disabled";
};

View File

@@ -341,6 +341,43 @@ static bool analogix_dp_get_vrr_capable(struct analogix_dp_device *dp)
return true;
}
static int analogix_dp_enable_sink_to_assr_mode(struct analogix_dp_device *dp, bool enable)
{
u8 data;
int ret;
ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_CONFIGURATION_SET, &data);
if (ret != 1)
return ret;
if (enable)
ret = drm_dp_dpcd_writeb(&dp->aux, DP_EDP_CONFIGURATION_SET,
data | DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
else
ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
data & ~DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
return ret < 0 ? ret : 0;
}
static int analogix_dp_set_assr_mode(struct analogix_dp_device *dp)
{
bool assr_en;
int ret;
assr_en = drm_dp_alternate_scrambler_reset_cap(dp->dpcd);
ret = analogix_dp_enable_sink_to_assr_mode(dp, assr_en);
if (ret < 0)
return ret;
analogix_dp_enable_assr_mode(dp, assr_en);
dp->link_train.assr = assr_en;
return 0;
}
static int analogix_dp_link_start(struct analogix_dp_device *dp)
{
u8 buf[4];
@@ -380,6 +417,13 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
if (retval < 0)
return retval;
/* set ASSR if available */
retval = analogix_dp_set_assr_mode(dp);
if (retval < 0) {
dev_err(dp->dev, "failed to set assr mode\n");
return retval;
}
/* set enhanced mode if available */
retval = analogix_dp_set_enhanced_mode(dp);
if (retval < 0) {
@@ -908,6 +952,7 @@ static int analogix_dp_fast_link_train(struct analogix_dp_device *dp)
analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
analogix_dp_set_lane_link_training(dp);
analogix_dp_enable_assr_mode(dp, dp->link_train.assr);
analogix_dp_enable_enhanced_mode(dp, dp->link_train.enhanced_framing);
/* source Set training pattern 1 */
@@ -2392,6 +2437,7 @@ static void analogix_dp_link_train_restore(struct analogix_dp_device *dp)
dp->link_train.link_rate = link_rate;
dp->link_train.lane_count = lane_count;
dp->link_train.assr = analogix_dp_get_assr_mode(dp);
dp->link_train.enhanced_framing = analogix_dp_get_enhanced_mode(dp);
dp->link_train.ssc = !!(spread & DP_MAX_DOWNSPREAD_0_5);

View File

@@ -160,6 +160,7 @@ struct link_train {
u8 training_lane[4];
bool ssc;
bool enhanced_framing;
bool assr;
enum link_training_state lt_state;
};
@@ -279,5 +280,7 @@ void analogix_dp_init(struct analogix_dp_device *dp);
void analogix_dp_irq_handler(struct analogix_dp_device *dp);
void analogix_dp_phy_test(struct analogix_dp_device *dp);
void analogix_dp_check_device_service_irq(struct analogix_dp_device *dp);
void analogix_dp_enable_assr_mode(struct analogix_dp_device *dp, bool enable);
bool analogix_dp_get_assr_mode(struct analogix_dp_device *dp);
#endif /* _ANALOGIX_DP_CORE_H */

View File

@@ -1390,3 +1390,27 @@ void analogix_dp_init(struct analogix_dp_device *dp)
analogix_dp_init_hpd(dp);
analogix_dp_init_aux(dp);
}
void analogix_dp_enable_assr_mode(struct analogix_dp_device *dp, bool enable)
{
u32 reg;
if (enable) {
reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY);
reg |= ALTERNATE_SR_ENABLE;
analogix_dp_write(dp, ANALOGIX_DP_LINK_POLICY, reg);
} else {
reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY);
reg &= ~ALTERNATE_SR_ENABLE;
analogix_dp_write(dp, ANALOGIX_DP_LINK_POLICY, reg);
}
}
bool analogix_dp_get_assr_mode(struct analogix_dp_device *dp)
{
u32 reg;
reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY);
return !!(reg & ALTERNATE_SR_ENABLE);
}

View File

@@ -146,6 +146,8 @@
#define ANALOGIX_DP_CRC_CON 0x890
#define ANALOGIX_DP_I2S_CTRL 0x9C8
#define ANALOGIX_DP_LINK_POLICY 0x9D8
/* ANALOGIX_DP_TX_SW_RESET */
#define RESET_DP_TX (0x1 << 0)
@@ -515,4 +517,7 @@
/* ANALOGIX_DP_I2S_CTRL */
#define I2S_EN (0x1 << 4)
/* ANALOGIX_DP_LINK_POLICY */
#define ALTERNATE_SR_ENABLE (0x1 << 7)
#endif /* _ANALOGIX_DP_REG_H */

View File

@@ -151,7 +151,7 @@
#define DSI2_IPI_VID_VACT_MAN_CFG 0X0334
#define VID_VACT_LINES(x) UPDATE(x, 13, 0)
#define DSI2_IPI_VID_VFP_MAN_CFG 0X033C
#define VID_VFP_LINES(x) UPDATE(x, 9, 0)
#define VID_VFP_LINES(x) UPDATE(x, 12, 0)
#define DSI2_IPI_PIX_PKT_CFG 0x0344
#define MAX_PIX_PKT(x) UPDATE(x, 15, 0)
@@ -227,7 +227,9 @@ struct dw_mipi_dsi2_plat_data {
const u32 *dsi1_grf_reg_fields;
unsigned long long dphy_max_bit_rate_per_lane;
unsigned long long cphy_max_symbol_rate_per_lane;
const u32 max_vfp;
const u32 max_vsync;
const u32 max_vbp;
};
struct dw_mipi_dsi2 {
@@ -1213,10 +1215,11 @@ dw_mipi_dsi2_connector_mode_valid(struct drm_connector *connector,
if (vm.vactive > 16383)
return MODE_VIRTUAL_Y;
if (vm.vsync_len > 1023)
if (vm.vsync_len > dsi2->pdata->max_vsync)
return MODE_VSYNC_WIDE;
if (vm.vback_porch > 1023 || vm.vfront_porch > 1023)
if (vm.vback_porch > dsi2->pdata->max_vbp ||
vm.vfront_porch > dsi2->pdata->max_vfp)
return MODE_VBLANK_WIDE;
/*
@@ -2056,6 +2059,9 @@ static const struct dw_mipi_dsi2_plat_data rk3576_mipi_dsi2_plat_data = {
.dsi0_grf_reg_fields = rk3576_dsi_grf_reg_fields,
.dphy_max_bit_rate_per_lane = 2500000000ULL,
.cphy_max_symbol_rate_per_lane = 1700000000ULL,
.max_vfp = 8191,
.max_vsync = 1023,
.max_vbp = 1023,
};
static const struct dw_mipi_dsi2_plat_data rk3588_mipi_dsi2_plat_data = {
@@ -2064,6 +2070,9 @@ static const struct dw_mipi_dsi2_plat_data rk3588_mipi_dsi2_plat_data = {
.dsi1_grf_reg_fields = rk3588_dsi1_grf_reg_fields,
.dphy_max_bit_rate_per_lane = 4500000000ULL,
.cphy_max_symbol_rate_per_lane = 2000000000ULL,
.max_vfp = 1023,
.max_vsync = 1023,
.max_vbp = 1023,
};
static const struct of_device_id dw_mipi_dsi2_dt_ids[] = {

View File

@@ -858,6 +858,11 @@ struct vop2_video_port {
* @irq: independent irq for each vp
*/
int irq;
/**
* @sharp_disabled: Sharp is mutually exclusive with post-scaler and split,
* we configure whether sharp is disabled in dts
*/
bool sharp_disabled;
};
struct vop2_extend_pll {
@@ -4578,7 +4583,7 @@ static void vop2_initial(struct drm_crtc *crtc)
* After vop initialization, keep sw_sharp_enable always on.
* Only enable/disable sharp submodule to avoid black screen.
*/
if (vp_data->feature & VOP_FEATURE_POST_SHARP)
if (vp_data->feature & VOP_FEATURE_POST_SHARP && vp->sharp_disabled)
writel(0x1, vop2->sharp_res.regs);
/* disable immediately enable bit for dp */
@@ -9507,6 +9512,27 @@ static void vop2_setup_dual_channel_if(struct drm_crtc *crtc)
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct vop2 *vop2 = vp->vop2;
const struct vop2_data *vop2_data = vop2->data;
const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
/*
* RK3576 VOP split and post-scaler use the same line buffer.
* If enable split, post-scaler must be disabled.
*/
if (vop2->version == VOP_VERSION_RK3576) {
DRM_ERROR("split is enabled, post-scaler shouldn't be set\n");
vcstate->left_margin = 100;
vcstate->right_margin = 100;
vcstate->top_margin = 100;
vcstate->bottom_margin = 100;
}
/*
* VOP split and sharp use the same line buffer. If enable
* split, sharp must be disabled completely.
*/
if (vp_data->feature & VOP_FEATURE_POST_SHARP)
writel(0, vop2->sharp_res.regs);
if (output_if_is_lvds(vcstate->output_if) &&
(vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE)) {
@@ -9818,6 +9844,15 @@ static inline char *vop2_output_if_to_string(unsigned long inf)
ARRAY_SIZE(vop2_output_if_name_list));
}
static bool vop2_is_left_right_or_odd_even_mode(struct rockchip_crtc_state *vcstate)
{
if (!(vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) &&
!(vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE))
return false;
return true;
}
static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
@@ -10038,8 +10073,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
}
}
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE ||
vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE)
if (vop2_is_left_right_or_odd_even_mode(vcstate))
vop2_setup_dual_channel_if(crtc);
if (vcstate->output_if & VOP_OUTPUT_IF_eDP0) {
@@ -12470,6 +12504,17 @@ static void vop2_post_sharp_config(struct drm_crtc *crtc)
struct post_sharp *post_sharp;
int i;
if (vp->sharp_disabled)
return;
if (vop2_is_left_right_or_odd_even_mode(vcstate)) {
if (post_sharp_enabled(crtc))
DRM_WARN("split is enabled, can't enable sharp\n");
vcstate->sharp_en = false;
return;
}
/* sharp work in yuv color space, if it is rgb overlay sharp shouldn't be enabled */
if (!vcstate->yuv_overlay || !post_sharp_enabled(crtc)) {
/*
@@ -13089,6 +13134,7 @@ static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc,
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);
struct drm_mode_config *mode_config = &drm_dev->mode_config;
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
bool replaced = false;
int ret;
@@ -13097,6 +13143,12 @@ static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc,
DRM_ERROR("sharp is enabled, failed to set %s\n", property->name);
return 0;
}
if (vop2_is_left_right_or_odd_even_mode(vcstate) &&
vop2->version == VOP_VERSION_RK3576) {
DRM_ERROR("split is enabled, failed to set %s\n", property->name);
return 0;
}
vcstate->left_margin = val;
return 0;
}
@@ -13106,6 +13158,12 @@ static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc,
DRM_ERROR("sharp is enabled, failed to set %s\n", property->name);
return 0;
}
if (vop2_is_left_right_or_odd_even_mode(vcstate) &&
vop2->version == VOP_VERSION_RK3576) {
DRM_ERROR("split is enabled, failed to set %s\n", property->name);
return 0;
}
vcstate->right_margin = val;
return 0;
}
@@ -13115,6 +13173,12 @@ static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc,
DRM_ERROR("sharp is enabled, failed to set %s\n", property->name);
return 0;
}
if (vop2_is_left_right_or_odd_even_mode(vcstate) &&
vop2->version == VOP_VERSION_RK3576) {
DRM_ERROR("split is enabled, failed to set %s\n", property->name);
return 0;
}
vcstate->top_margin = val;
return 0;
}
@@ -13124,6 +13188,12 @@ static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc,
DRM_ERROR("sharp is enabled, failed to set %s\n", property->name);
return 0;
}
if (vop2_is_left_right_or_odd_even_mode(vcstate) &&
vop2->version == VOP_VERSION_RK3576) {
DRM_ERROR("split is enabled, failed to set %s\n", property->name);
return 0;
}
vcstate->bottom_margin = val;
return 0;
}
@@ -14319,6 +14389,8 @@ static int vop2_create_crtc(struct vop2 *vop2, uint8_t enabled_vp_mask)
crtc->port = port;
of_property_read_u32(port, "cursor-win-id", &vp->cursor_win_id);
vp->sharp_disabled = of_property_read_bool(port, "sharp-disabled");
plane_mask = vp->plane_mask;
if (vop2_soc_is_rk3566()) {
if ((vp->plane_mask & RK3566_MIRROR_PLANE_MASK) &&

View File

@@ -80,10 +80,10 @@ struct rockchip_saradc {
bool suspended;
#ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN
bool test;
u32 chn;
spinlock_t lock;
struct workqueue_struct *wq;
struct delayed_work work;
u32 test_chn;
spinlock_t test_lock;
struct workqueue_struct *test_wq;
struct delayed_work test_work;
#endif
};
@@ -138,7 +138,7 @@ static int rockchip_saradc_read_v2(struct rockchip_saradc *info)
writel_relaxed(0x1, info->regs + SARADC2_END_INT_ST);
#ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN
channel = info->chn;
channel = info->test_chn;
#else
channel = info->last_chan->channel;
#endif
@@ -229,6 +229,10 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
unsigned long flags;
#endif
/* Nothing need to do if info->last_chan not ready */
if (!info->last_chan)
return IRQ_HANDLED;
/* Read value */
info->last_val = rockchip_saradc_read(info);
#ifndef CONFIG_ROCKCHIP_SARADC_TEST_CHN
@@ -239,12 +243,13 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
complete(&info->completion);
#ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN
spin_lock_irqsave(&info->lock, flags);
spin_lock_irqsave(&info->test_lock, flags);
if (info->test) {
pr_info("chn[%d] val = %d\n", info->chn, info->last_val);
mod_delayed_work(info->wq, &info->work, msecs_to_jiffies(100));
pr_info("chn[%d] val = %d\n", info->test_chn, info->last_val);
mod_delayed_work(info->test_wq, &info->test_work,
msecs_to_jiffies(100));
}
spin_unlock_irqrestore(&info->lock, flags);
spin_unlock_irqrestore(&info->test_lock, flags);
#endif
return IRQ_HANDLED;
}
@@ -538,22 +543,23 @@ static ssize_t saradc_test_chn_store(struct device *dev,
if (err)
return err;
spin_lock_irqsave(&info->lock, flags);
spin_lock_irqsave(&info->test_lock, flags);
if (val > SARADC_CTRL_CHN_MASK && info->test) {
info->test = false;
spin_unlock_irqrestore(&info->lock, flags);
cancel_delayed_work_sync(&info->work);
spin_unlock_irqrestore(&info->test_lock, flags);
cancel_delayed_work_sync(&info->test_work);
return size;
}
if (!info->test && val <= SARADC_CTRL_CHN_MASK) {
info->test = true;
info->chn = val;
mod_delayed_work(info->wq, &info->work, msecs_to_jiffies(100));
info->test_chn = val;
mod_delayed_work(info->test_wq, &info->test_work,
msecs_to_jiffies(100));
}
spin_unlock_irqrestore(&info->lock, flags);
spin_unlock_irqrestore(&info->test_lock, flags);
return size;
}
@@ -580,15 +586,15 @@ static void rockchip_saradc_destroy_wq(void *data)
{
struct rockchip_saradc *info = data;
destroy_workqueue(info->wq);
destroy_workqueue(info->test_wq);
}
static void rockchip_saradc_test_work(struct work_struct *work)
{
struct rockchip_saradc *info = container_of(work,
struct rockchip_saradc, work.work);
struct rockchip_saradc, test_work.work);
rockchip_saradc_start(info, info->chn);
rockchip_saradc_start(info, info->test_chn);
}
#endif
@@ -748,9 +754,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
return ret;
#ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN
info->wq = create_singlethread_workqueue("adc_wq");
INIT_DELAYED_WORK(&info->work, rockchip_saradc_test_work);
spin_lock_init(&info->lock);
info->test_wq = create_singlethread_workqueue("adc_wq");
INIT_DELAYED_WORK(&info->test_work, rockchip_saradc_test_work);
spin_lock_init(&info->test_lock);
ret = sysfs_create_group(&pdev->dev.kobj, &rockchip_saradc_attr_group);
if (ret)
return ret;

View File

@@ -55,9 +55,10 @@ int rkisp_dvbm_init(struct rkisp_stream *stream)
dvbm_cfg.cbuf_top = dvbm_cfg.cbuf_bot + (width * wrap_line / 2);
dvbm_cfg.cbuf_lstd = width;
dvbm_cfg.cbuf_fstd = dvbm_cfg.ybuf_fstd / 2;
dvbm_cfg.chan_id = dev->dev_id;
rk_dvbm_ctrl(g_dvbm, DVBM_ISP_SET_CFG, &dvbm_cfg);
rk_dvbm_link(g_dvbm);
rk_dvbm_link(g_dvbm, dev->dev_id);
return 0;
}
@@ -67,7 +68,7 @@ void rkisp_dvbm_deinit(struct rkisp_device *dev)
pr_err("g_dvbm %p or devv %p is NULL\n", g_dvbm, dev);
return;
}
rk_dvbm_unlink(g_dvbm);
rk_dvbm_unlink(g_dvbm, dev->dev_id);
}
int rkisp_dvbm_event(struct rkisp_device *dev, u32 event)

View File

@@ -1,442 +0,0 @@
/*
* gpio detection driver
*
* Copyright (C) 2015 Rockchip Electronics Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/gpio_detection.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/wakelock.h>
#include <linux/rk_keys.h>
#include <linux/gpio/consumer.h>
#define WAKE_LOCK_TIMEOUT_MS (5000)
struct gpio_data {
struct gpio_detection *parent;
const char *name;
struct device dev;
int notify;
struct gpio_desc *gpio;
int val;
int irq;
struct delayed_work work;
unsigned int debounce_ms;
int wakeup;
};
struct gpio_detection {
struct class_attribute cls_attr;
struct device *dev;
int num;
struct gpio_data *data;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct notifier_block fb_notifier;
struct wake_lock wake_lock;
int mirror;
int type;
int info;
};
static struct class *gpio_detection_class;
static BLOCKING_NOTIFIER_HEAD(gpio_det_notifier_list);
static int system_suspend;
#if IS_ENABLED(CONFIG_GPIO_DET)
/*
* gpio_det_notifier_call_chain - notify clients of gpio_det_events
*
*/
int gpio_det_notifier_call_chain(unsigned long val, void *v)
{
return blocking_notifier_call_chain(&gpio_det_notifier_list, val, v);
}
EXPORT_SYMBOL_GPL(gpio_det_notifier_call_chain);
/*
* gpio_det_register_notifier - register a client notifier
* @nb: notifier block to callback on events
*/
int gpio_det_register_notifier(struct notifier_block *nb)
{
int ret = blocking_notifier_chain_register(&gpio_det_notifier_list, nb);
return ret;
}
EXPORT_SYMBOL(gpio_det_register_notifier);
/*
* gpio_det_unregister_client - unregister a client notifier
* @nb: notifier block to callback on events
*/
int gpio_det_unregister_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&gpio_det_notifier_list, nb);
}
EXPORT_SYMBOL(gpio_det_unregister_notifier);
#endif
static void gpio_det_report_event(struct gpio_data *gpiod)
{
struct gpio_event event;
struct gpio_detection *gpio_det = gpiod->parent;
char *status = NULL;
char *envp[2];
event.val = gpiod->val;
event.name = gpiod->name;
status = kasprintf(GFP_KERNEL, "GPIO_NAME=%s GPIO_STATE=%s",
gpiod->name, event.val ? "over" : "on");
envp[0] = status;
envp[1] = NULL;
wake_lock_timeout(&gpio_det->wake_lock,
msecs_to_jiffies(WAKE_LOCK_TIMEOUT_MS));
kobject_uevent_env(&gpiod->dev.kobj, KOBJ_CHANGE, envp);
if (gpiod->notify)
gpio_det_notifier_call_chain(GPIO_EVENT, &event);
kfree(status);
}
static void gpio_det_work_func(struct work_struct *work)
{
struct gpio_data *gpiod = container_of(work, struct gpio_data,
work.work);
int val = gpiod_get_value(gpiod->gpio);
if (gpiod->val != val) {
gpiod->val = val;
gpio_det_report_event(gpiod);
if (system_suspend && gpiod->wakeup) {
rk_send_power_key(1);
rk_send_power_key(0);
}
}
}
static irqreturn_t gpio_det_interrupt(int irq, void *dev_id)
{
struct gpio_data *gpiod = dev_id;
int val = gpiod_get_raw_value(gpiod->gpio);
unsigned int irqflags = IRQF_ONESHOT;
if (val)
irqflags |= IRQ_TYPE_EDGE_FALLING;
else
irqflags |= IRQ_TYPE_EDGE_RISING;
irq_set_irq_type(gpiod->irq, irqflags);
mod_delayed_work(system_wq, &gpiod->work,
msecs_to_jiffies(gpiod->debounce_ms));
return IRQ_HANDLED;
}
static int gpio_det_init_status_check(struct gpio_detection *gpio_det)
{
struct gpio_data *gpiod;
int i;
for (i = 0; i < gpio_det->num; i++) {
gpiod = &gpio_det->data[i];
gpiod->val = gpiod_get_value(gpiod->gpio);
if (gpiod->val)
gpio_det_report_event(gpiod);
}
return 0;
}
static int gpio_det_fb_notifier_callback(struct notifier_block *self,
unsigned long event,
void *data)
{
struct gpio_detection *gpio_det;
struct fb_event *evdata = data;
int fb_blank;
if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
return 0;
gpio_det = container_of(self, struct gpio_detection, fb_notifier);
fb_blank = *(int *)evdata->data;
if (fb_blank == FB_BLANK_UNBLANK)
system_suspend = 0;
else
system_suspend = 1;
return 0;
}
static int gpio_det_fb_notifier_register(struct gpio_detection *gpio)
{
gpio->fb_notifier.notifier_call = gpio_det_fb_notifier_callback;
return fb_register_client(&gpio->fb_notifier);
}
static ssize_t gpio_detection_info_show(struct class *class,
struct class_attribute *attr,
char *buf)
{
struct gpio_detection *gpio_det;
gpio_det = container_of(attr, struct gpio_detection, cls_attr);
return sprintf(buf, "%d\n", gpio_det->info);
}
static ssize_t status_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct gpio_data *gpiod = container_of(dev, struct gpio_data, dev);
unsigned int val = gpiod_get_value(gpiod->gpio);
return sprintf(buf, "%d\n", val);
}
static ssize_t status_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct gpio_data *gpiod;
int val;
int ret;
struct gpio_event event;
gpiod = container_of(dev, struct gpio_data, dev);
ret = kstrtoint(buf, 0, &val);
if (ret < 0)
return ret;
if (val >= 0) {
event.val = val;
event.name = gpiod->name;
gpio_det_notifier_call_chain(GPIO_EVENT, &event);
} else {
gpiod->notify = 0;
}
return count;
}
static DEVICE_ATTR_RW(status);
static struct attribute *gpio_detection_attrs[] = {
&dev_attr_status.attr,
NULL,
};
ATTRIBUTE_GROUPS(gpio_detection);
static int __init gpio_deteciton_class_init(void)
{
gpio_detection_class = class_create(THIS_MODULE, "gpio-detection");
if (IS_ERR(gpio_detection_class)) {
pr_err("create gpio_detection class failed (%ld)\n",
PTR_ERR(gpio_detection_class));
return PTR_ERR(gpio_detection_class);
}
return 0;
}
static int gpio_detection_class_register(struct gpio_detection *gpio_det,
struct gpio_data *gpiod)
{
int ret;
gpiod->dev.class = gpio_detection_class;
dev_set_name(&gpiod->dev, "%s", gpiod->name);
dev_set_drvdata(&gpiod->dev, gpio_det);
ret = device_register(&gpiod->dev);
ret = sysfs_create_groups(&gpiod->dev.kobj, gpio_detection_groups);
return ret;
}
static int gpio_det_parse_dt(struct gpio_detection *gpio_det,
struct platform_device *pdev)
{
struct gpio_data *data;
struct device *dev = &pdev->dev;
struct device_node *node;
struct gpio_data *gpiod;
struct fwnode_handle *child;
int count = 0;
int i = 0;
int num = 0;
num = of_get_child_count(gpio_det->dev->of_node);
count = device_get_child_node_count(dev);
if (!count || !num)
return -ENODEV;
data = devm_kzalloc(gpio_det->dev, num * sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
of_property_read_u32(gpio_det->dev->of_node, "rockchip,camcap-type",
&gpio_det->type);
of_property_read_u32(gpio_det->dev->of_node, "rockchip,camcap-mirror",
&gpio_det->mirror);
gpio_det->info = (gpio_det->mirror << 4) | gpio_det->type;
device_for_each_child_node(dev, child) {
node = to_of_node(child);
gpiod = &data[i++];
gpiod->parent = gpio_det;
gpiod->notify = 1;
gpiod->name = of_get_property(node, "label", NULL);
gpiod->wakeup = !!of_get_property(node, "gpio,wakeup", NULL);
of_property_read_u32(node, "linux,debounce-ms",
&gpiod->debounce_ms);
if (!strcmp(gpiod->name, "car-reverse"))
gpiod->gpio = devm_get_gpiod_from_child(dev,
"car-reverse", child);
else
gpiod->gpio = devm_get_gpiod_from_child(dev,
"car-acc", child);
}
gpio_det->num = num;
gpio_det->data = data;
return 0;
}
static int gpio_det_probe(struct platform_device *pdev)
{
struct gpio_detection *gpio_det;
struct gpio_data *gpiod;
unsigned long irqflags = IRQF_ONESHOT;
int i;
int ret;
gpio_det = devm_kzalloc(&pdev->dev, sizeof(*gpio_det), GFP_KERNEL);
if (!gpio_det)
return -ENOMEM;
gpio_det->dev = &pdev->dev;
gpio_det->cls_attr.attr.name = "info";
gpio_det->cls_attr.attr.mode = S_IRUGO;
gpio_det->cls_attr.show = gpio_detection_info_show;
dev_set_name(gpio_det->dev, "gpio_detection");
if (!pdev->dev.of_node)
return -EINVAL;
gpio_det->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(gpio_det->pinctrl)) {
dev_err(&pdev->dev, "pinctrl get failed\n");
return PTR_ERR(gpio_det->pinctrl);
}
gpio_det->pins_default = pinctrl_lookup_state(gpio_det->pinctrl,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(gpio_det->pins_default))
dev_err(gpio_det->dev, "get default pinstate failed\n");
else
pinctrl_select_state(gpio_det->pinctrl, gpio_det->pins_default);
if (gpio_det_parse_dt(gpio_det, pdev))
return -ENODEV;
wake_lock_init(&gpio_det->wake_lock, WAKE_LOCK_SUSPEND,
"gpio_detection");
for (i = 0; i < gpio_det->num; i++) {
gpiod = &gpio_det->data[i];
gpiod_direction_input(gpiod->gpio);
gpiod->irq = gpiod_to_irq(gpiod->gpio);
if (gpiod->irq < 0) {
dev_err(gpio_det->dev, "failed to get irq number for GPIO %s\n",
gpiod->name);
continue;
}
ret = gpio_detection_class_register(gpio_det, gpiod);
if (ret < 0)
return ret;
INIT_DELAYED_WORK(&gpiod->work, gpio_det_work_func);
gpiod->val = gpiod_get_raw_value(gpiod->gpio);
if (gpiod->val)
irqflags |= IRQ_TYPE_EDGE_FALLING;
else
irqflags |= IRQ_TYPE_EDGE_RISING;
ret = devm_request_threaded_irq(gpio_det->dev, gpiod->irq,
NULL, gpio_det_interrupt,
irqflags | IRQF_ONESHOT,
gpiod->name, gpiod);
if (ret < 0)
dev_err(gpio_det->dev, "request irq(%s) failed:%d\n",
gpiod->name, ret);
else
if (gpiod->wakeup)
enable_irq_wake(gpiod->irq);
}
if (gpio_det->info) {
ret = class_create_file(gpio_detection_class,
&gpio_det->cls_attr);
if (ret)
dev_warn(gpio_det->dev, "create class file failed:%d\n",
ret);
}
gpio_det_fb_notifier_register(gpio_det);
gpio_det_init_status_check(gpio_det);
dev_info(gpio_det->dev, "gpio detection driver probe success\n");
return 0;
}
#if defined(CONFIG_OF)
static const struct of_device_id gpio_det_of_match[] = {
{
.compatible = "gpio-detection"
},
{},
};
#endif
static struct platform_driver gpio_det_driver = {
.driver = {
.name = "gpio-detection",
.of_match_table = of_match_ptr(gpio_det_of_match),
},
.probe = gpio_det_probe,
};
#ifdef CONFIG_VIDEO_REVERSE_IMAGE
int gpio_det_init(void)
#else
static int __init gpio_det_init(void)
#endif
{
if (!gpio_deteciton_class_init())
return platform_driver_register(&gpio_det_driver);
else
return -1;
}
#ifndef CONFIG_VIDEO_REVERSE_IMAGE
fs_initcall_sync(gpio_det_init);
#endif
static void __exit gpio_det_exit(void)
{
platform_driver_unregister(&gpio_det_driver);
}
module_exit(gpio_det_exit);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:gpio-detection");
MODULE_AUTHOR("ROCKCHIP");

View File

@@ -1,192 +0,0 @@
/*
* drivers/misc/usb_cam_gpio.c
*
* Copyright (C) 2012-2016 Rockchip Electronics Co., Ltd.
* Author: Bin Yang <yangbin@rock-chips.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/freezer.h>
#include <linux/of_gpio.h>
static struct class *usb_cam_gpio_class;
struct usb_cam_gpio {
struct device *dev;
struct device sys_dev;
struct gpio_desc *gpio_cam_hd;
struct gpio_desc *gpio_cam_ir;
};
static ssize_t hd_camera_on_show(struct device *sys_dev,
struct device_attribute *attr,
char *buf)
{
struct usb_cam_gpio *gpiod = container_of(sys_dev, struct usb_cam_gpio,
sys_dev);
return sprintf(buf, "%d\n", gpiod_get_value(gpiod->gpio_cam_hd));
}
static ssize_t hd_camera_on_store(struct device *sys_dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_cam_gpio *gpiod = container_of(sys_dev, struct usb_cam_gpio,
sys_dev);
int val = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &val);
if (ret < 0)
return ret;
if (val)
val = 1;
gpiod_set_value(gpiod->gpio_cam_hd, val);
return count;
}
static DEVICE_ATTR_RW(hd_camera_on);
static ssize_t ir_camera_on_show(struct device *sys_dev,
struct device_attribute *attr,
char *buf)
{
struct usb_cam_gpio *gpiod = container_of(sys_dev,
struct usb_cam_gpio, sys_dev);
return sprintf(buf, "%d\n", gpiod_get_value(gpiod->gpio_cam_ir));
}
static ssize_t ir_camera_on_store(struct device *sys_dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_cam_gpio *gpiod = container_of(sys_dev,
struct usb_cam_gpio, sys_dev);
int val;
int ret;
ret = kstrtoint(buf, 0, &val);
if (ret < 0)
return ret;
if (val)
val = 1;
gpiod_set_value(gpiod->gpio_cam_ir, val);
return count;
}
static DEVICE_ATTR_RW(ir_camera_on);
static struct attribute *usb_cam_gpio_attrs[] = {
&dev_attr_hd_camera_on.attr,
&dev_attr_ir_camera_on.attr,
NULL,
};
ATTRIBUTE_GROUPS(usb_cam_gpio);
static int usb_cam_gpio_device_register(struct usb_cam_gpio *gpiod)
{
int ret;
struct device *dev = &gpiod->sys_dev;
const char *name = {"usb_camera_on"};
dev->class = usb_cam_gpio_class;
dev_set_name(dev, "%s", name);
dev_set_drvdata(dev, gpiod);
ret = device_register(dev);
return ret;
}
static int usb_cam_gpio_probe(struct platform_device *pdev)
{
struct usb_cam_gpio *gpiod;
int ret = 0;
usb_cam_gpio_class = class_create(THIS_MODULE, "usb_cam_gpio");
if (IS_ERR(usb_cam_gpio_class)) {
pr_err("create uvc_detection class failed (%ld)\n",
PTR_ERR(usb_cam_gpio_class));
return PTR_ERR(usb_cam_gpio_class);
}
usb_cam_gpio_class->dev_groups = usb_cam_gpio_groups;
gpiod = devm_kzalloc(&pdev->dev, sizeof(*gpiod), GFP_KERNEL);
if (!gpiod)
return -ENOMEM;
gpiod->dev = &pdev->dev;
gpiod->gpio_cam_hd = devm_gpiod_get_optional(gpiod->dev,
"hd-cam", GPIOD_OUT_LOW);
if (IS_ERR(gpiod->gpio_cam_hd)) {
dev_warn(gpiod->dev, "Could not get hd-cam-gpios!\n");
gpiod->gpio_cam_hd = NULL;
}
gpiod->gpio_cam_ir = devm_gpiod_get_optional(gpiod->dev,
"ir-cam", GPIOD_OUT_HIGH);
if (IS_ERR(gpiod->gpio_cam_ir)) {
dev_warn(gpiod->dev, "Could not get ir-cam-gpios!\n");
gpiod->gpio_cam_ir = NULL;
}
ret = usb_cam_gpio_device_register(gpiod);
if (ret < 0) {
dev_err(gpiod->dev, "usb_cam_gpio device register fail\n");
return ret;
}
dev_info(gpiod->dev, "usb_cam_gpio_probe success\n");
return 0;
}
static const struct of_device_id usb_cam_gpio_match[] = {
{ .compatible = "usb-cam-gpio" },
{ /* Sentinel */ }
};
static int usb_cam_gpio_remove(struct platform_device *pdev)
{
if (!IS_ERR(usb_cam_gpio_class))
class_destroy(usb_cam_gpio_class);
return 0;
}
static struct platform_driver usb_cam_gpio_driver = {
.probe = usb_cam_gpio_probe,
.remove = usb_cam_gpio_remove,
.driver = {
.name = "usb_cam_gpio",
.owner = THIS_MODULE,
.of_match_table = usb_cam_gpio_match,
},
};
module_platform_driver(usb_cam_gpio_driver);
MODULE_ALIAS("platform:usb_cam_gpio");
MODULE_AUTHOR("Bin Yang <yangbin@rock-chips.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("usb camera gpio driver");

View File

@@ -1,466 +0,0 @@
/*
* ec battery driver
*
* Copyright (C) 2016 Rockchip Electronics Co., Ltd.
* Shunqing Chen <csq@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/power_supply.h>
static int dbg_enable;
module_param_named(dbg_level, dbg_enable, int, 0644);
#define DBG(args...) \
do { \
if (dbg_enable) { \
printk(args); \
} \
} while (0)
struct ec_battery {
struct i2c_client *i2c;
struct device *dev;
struct regmap *regmap;
struct power_supply *bat;
struct workqueue_struct *bat_monitor_wq;
struct delayed_work bat_delay_work;
u32 monitor_sec;
u32 bat_mode;
u16 status;
int current_now;
u16 voltage_now;
u16 rem_capacity;
u16 full_charge_capacity;
u16 design_capacity;
int temperature_now;
int soc;
bool is_charge;
bool dis_charge;
bool is_ctitical;
bool is_battery_low;
bool is_battery_in;
bool is_ac_in;
struct gpio_desc *ec_notify_io;
};
enum bat_mode {
MODE_BATTARY = 0,
MODE_VIRTUAL,
};
/* virtual params */
#define VIRTUAL_CURRENT 1000
#define VIRTUAL_VOLTAGE 3888
#define VIRTUAL_SOC 66
#define VIRTUAL_PRESET 1
#define VIRTUAL_TEMPERATURE 188
#define VIRTUAL_STATUS POWER_SUPPLY_STATUS_CHARGING
#define TIMER_MS_COUNTS 1000
#define DEFAULT_MONITOR_SEC 5
#define EC_GET_VERSION_COMMOND 0x10
#define EC_GET_VERSION_INFO_NUM (5)
#define EC_GET_BATTERY_INFO_COMMOND 0x07
#define EC_GET_PARAMETER_NUM (13)
#define EC_GET_BATTERY_OTHER_COMMOND 0x08
#define EC_GET_BATTERYINFO_NUM (7)
#define EC_GET_BIT(a, b) (((a) & (1 << (b))) ? 1 : 0)
#define EC_DIS_CHARGE(a) EC_GET_BIT(a, 0)
#define EC_IS_CHARGE(a) EC_GET_BIT(a, 1)
#define EC_IS_CRITICAL(a) EC_GET_BIT(a, 2)
#define EC_IS_BATTERY_LOW(a) EC_GET_BIT(a, 3)
#define EC_IS_BATTERY_IN(a) EC_GET_BIT(a, 6)
#define EC_IS_AC_IN(a) EC_GET_BIT(a, 7)
static int ec_i2c_read(struct ec_battery *bat, u8 cmd, u8 *dest, u16 len)
{
struct i2c_client *i2c = bat->i2c;
int ret;
struct i2c_msg msg[2];
u8 buf[2];
buf[0] = cmd; /* EC_GET_BATTERY_INFO_COMMOND; */
msg[0].addr = i2c->addr;
msg[0].flags = i2c->flags & I2C_M_TEN;
msg[0].len = 1;
msg[0].buf = buf;
msg[1].addr = i2c->addr;
msg[1].flags = i2c->flags & I2C_M_TEN;
msg[1].flags |= I2C_M_RD;
msg[1].len = len;
msg[1].buf = dest;
ret = i2c_transfer(i2c->adapter, msg, 2);
return ret;
}
static void ec_dump_info(struct ec_battery *bat)
{
int temp;
DBG("==========================================\n");
DBG("battery status: %x\n", bat->status);
temp = bat->temperature_now / 10;
DBG("Temp: %d K (%d C))\n", temp, (temp - 272));
DBG("current_now: %d ma\n", bat->current_now);
DBG("voltage_now: %d mv\n", bat->voltage_now);
DBG("Charge: %d %%\n", bat->soc);
DBG("Remaining: %d mAh\n", bat->rem_capacity);
DBG("Cap-full: %d mAh\n", bat->full_charge_capacity);
DBG("Design: %d mAh\n", bat->design_capacity);
DBG("==========================================\n");
}
static int ec_get_battery_info(struct ec_battery *bat)
{
u8 buf[13] = {0};
u16 voltage2;
u16 full_charge_capacity_1;
u16 design_capacity;
u16 cur;
int ret;
int soc;
ret = ec_i2c_read(bat, EC_GET_BATTERY_INFO_COMMOND, buf,
EC_GET_PARAMETER_NUM);
if ((EC_GET_PARAMETER_NUM - 1) == buf[0]) {
bat->status = buf[2] << 8 | buf[1];
cur = (buf[4] << 8 | buf[3]);
bat->current_now = cur;
if (buf[4] & 0x80) {
bat->current_now = (~cur) & 0xffff;
bat->current_now = -(bat->current_now);
}
bat->rem_capacity = buf[6] << 8 | buf[5];
bat->voltage_now = buf[8] << 8 | buf[7];
bat->full_charge_capacity = buf[10] << 8 | buf[9];
bat->temperature_now = buf[12] << 8 | buf[11];
soc = (bat->rem_capacity + bat->full_charge_capacity / 101) *
100 / bat->full_charge_capacity;
if (soc > 100)
bat->soc = 100;
else if (soc < 0)
bat->soc = 0;
else
bat->soc = soc;
} else {
dev_err(bat->dev, "get battery info from 0x07 erro\n");
}
ret = ec_i2c_read(bat, EC_GET_BATTERY_OTHER_COMMOND, buf,
EC_GET_BATTERYINFO_NUM);
if ((EC_GET_BATTERYINFO_NUM - 1) == buf[0]) {
full_charge_capacity_1 = buf[2] << 8 | buf[1];
voltage2 = buf[4] << 8 | buf[3]; /* the same to uppo */
design_capacity = buf[6] << 8 | buf[5]; /* the same to uppo */
bat->design_capacity = design_capacity;
}
ec_dump_info(bat);
return 0;
}
static int ec_get_current(struct ec_battery *bat)
{
return bat->current_now * 1000;
}
static int ec_get_voltage(struct ec_battery *bat)
{
return bat->voltage_now * 1000;
}
static int is_ec_bat_exist(struct ec_battery *bat)
{
int is_exist;
is_exist = EC_IS_BATTERY_IN(bat->status);
return is_exist;
}
static int ec_get_capacity(struct ec_battery *bat)
{
return bat->soc;
}
static int ec_get_temperature(struct ec_battery *bat)
{
int temp;
temp = bat->temperature_now - 2722;
return temp;
}
static int ec_bat_chrg_online(struct ec_battery *bat)
{
return EC_IS_CHARGE(bat->status);
}
#ifdef CONFIG_OF
static int ec_bat_parse_dt(struct ec_battery *bat)
{
int ret;
u32 out_value;
struct device_node *np = bat->dev->of_node;
bat->bat_mode = MODE_BATTARY;
bat->monitor_sec = DEFAULT_MONITOR_SEC * TIMER_MS_COUNTS;
ret = of_property_read_u32(np, "virtual_power", &bat->bat_mode);
if (ret < 0)
dev_err(bat->dev, "virtual_power missing!\n");
ret = of_property_read_u32(np, "monitor_sec", &out_value);
if (ret < 0)
dev_err(bat->dev, "monitor_sec missing!\n");
else
bat->monitor_sec = out_value * TIMER_MS_COUNTS;
bat->ec_notify_io =
devm_gpiod_get_optional(bat->dev, "ec-notify",
GPIOD_IN);
if (!IS_ERR_OR_NULL(bat->ec_notify_io))
gpiod_direction_output(bat->ec_notify_io, 0);
return 0;
}
#else
static int ec_bat_parse_dt(struct ec_battery *bat)
{
return -ENODEV;
}
#endif
static enum power_supply_property ec_bat_props[] = {
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_STATUS,
};
static int ec_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct ec_battery *bat = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = ec_get_current(bat);/*uA*/
if (bat->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_CURRENT * 1000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = ec_get_voltage(bat);/*uV*/
if (bat->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_VOLTAGE * 1000;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = is_ec_bat_exist(bat);
if (bat->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_PRESET;
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = ec_get_capacity(bat);
if (bat->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_SOC;
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = POWER_SUPPLY_HEALTH_GOOD;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = ec_get_temperature(bat);
if (bat->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_TEMPERATURE;
break;
case POWER_SUPPLY_PROP_STATUS:
if (bat->bat_mode == MODE_VIRTUAL)
val->intval = VIRTUAL_STATUS;
else if (ec_get_capacity(bat) == 100)
val->intval = POWER_SUPPLY_STATUS_FULL;
else if (ec_bat_chrg_online(bat))
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
default:
return -EINVAL;
}
return 0;
}
static const struct power_supply_desc ec_bat_desc = {
.name = "battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = ec_bat_props,
.num_properties = ARRAY_SIZE(ec_bat_props),
.get_property = ec_battery_get_property,
};
static int ec_bat_init_power_supply(struct ec_battery *bat)
{
struct power_supply_config psy_cfg = { .drv_data = bat, };
bat->bat = power_supply_register(bat->dev, &ec_bat_desc, &psy_cfg);
if (IS_ERR(bat->bat)) {
dev_err(bat->dev, "register bat power supply fail\n");
return PTR_ERR(bat->bat);
}
return 0;
}
static void ec_bat_power_supply_changed(struct ec_battery *ec_bat)
{
bool state_changed;
static int old_cap = -1;
static int old_temperature;
state_changed = false;
if (ec_get_capacity(ec_bat) != old_cap)
state_changed = true;
else if (ec_get_temperature(ec_bat) != old_temperature)
state_changed = true;
if (state_changed) {
power_supply_changed(ec_bat->bat);
old_cap = ec_get_capacity(ec_bat);
old_temperature = ec_get_temperature(ec_bat);
}
}
static void ec_battery_work(struct work_struct *work)
{
struct ec_battery *ec_bat =
container_of(work, struct ec_battery, bat_delay_work.work);
ec_get_battery_info(ec_bat);
ec_bat_power_supply_changed(ec_bat);
queue_delayed_work(ec_bat->bat_monitor_wq, &ec_bat->bat_delay_work,
msecs_to_jiffies(ec_bat->monitor_sec));
}
static int ec_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ec_battery *ec_bat;
int ret;
ec_bat = devm_kzalloc(&client->dev, sizeof(*ec_bat), GFP_KERNEL);
if (!ec_bat)
return -ENOMEM;
ec_bat->dev = &client->dev;
ec_bat->i2c = client;
i2c_set_clientdata(client, ec_bat);
ret = ec_bat_parse_dt(ec_bat);
if (ret < 0) {
dev_err(ec_bat->dev, "parse dt failed!\n");
return ret;
}
ret = ec_bat_init_power_supply(ec_bat);
if (ret) {
dev_err(ec_bat->dev, "init power supply fail!\n");
return ret;
}
ec_bat->bat_monitor_wq =
alloc_ordered_workqueue("%s",
WQ_MEM_RECLAIM | WQ_FREEZABLE,
"ec-bat-monitor-wq");
INIT_DELAYED_WORK(&ec_bat->bat_delay_work, ec_battery_work);
queue_delayed_work(ec_bat->bat_monitor_wq, &ec_bat->bat_delay_work,
msecs_to_jiffies(TIMER_MS_COUNTS * 5));
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int ec_bat_pm_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ec_battery *ec_bat = i2c_get_clientdata(client);
cancel_delayed_work_sync(&ec_bat->bat_delay_work);
if (!IS_ERR_OR_NULL(ec_bat->ec_notify_io))
gpiod_direction_output(ec_bat->ec_notify_io, 1);
return 0;
}
static int ec_bat_pm_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ec_battery *ec_bat = i2c_get_clientdata(client);
if (!IS_ERR_OR_NULL(ec_bat->ec_notify_io))
gpiod_direction_output(ec_bat->ec_notify_io, 0);
queue_delayed_work(ec_bat->bat_monitor_wq, &ec_bat->bat_delay_work,
msecs_to_jiffies(TIMER_MS_COUNTS * 1));
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ec_bat_pm_ops, ec_bat_pm_suspend, ec_bat_pm_resume);
static const struct i2c_device_id ec_battery_i2c_ids[] = {
{ "ec_battery" },
{ },
};
MODULE_DEVICE_TABLE(i2c, ec_battery_i2c_ids);
#ifdef CONFIG_OF
static const struct of_device_id ec_of_match[] = {
{ .compatible = "rockchip,ec-battery" },
{ },
};
MODULE_DEVICE_TABLE(of, ec_of_match);
#else
static const struct of_device_id ec_of_match[] = {
{ },
};
#endif
static struct i2c_driver ec_i2c_driver = {
.driver = {
.name = "ec_battery",
.pm = &ec_bat_pm_ops,
.of_match_table = ec_of_match,
},
.id_table = ec_battery_i2c_ids,
.probe = ec_charger_probe,
};
module_i2c_driver(ec_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ec-charger");
MODULE_AUTHOR("Shunqing Chen<csq@rock-chips.com>");

View File

@@ -1,401 +0,0 @@
/*
* sy6982c/sy6982e charger driver
*
* Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/extcon.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/power/rk_usbbc.h>
#include <linux/property.h>
#include <linux/rk_keys.h>
#include <linux/workqueue.h>
enum charger_t {
USB_TYPE_UNKNOWN_CHARGER,
USB_TYPE_NONE_CHARGER,
USB_TYPE_USB_CHARGER,
USB_TYPE_AC_CHARGER,
USB_TYPE_CDP_CHARGER,
DC_TYPE_DC_CHARGER,
DC_TYPE_NONE_CHARGER,
};
struct sy6982c_charger {
struct device *dev;
struct power_supply *usb_psy;
struct workqueue_struct *usb_charger_wq;
struct delayed_work usb_work;
struct workqueue_struct *dc_charger_wq;
struct delayed_work dc_work;
struct delayed_work discnt_work;
struct notifier_block cable_cg_nb;
struct notifier_block cable_discnt_nb;
unsigned int bc_event;
enum charger_t usb_charger;
enum charger_t dc_charger;
bool extcon;
struct extcon_dev *cable_edev;
struct gpio_desc *dc_det_pin;
bool support_dc_det;
};
static void sy6982c_cg_bc_evt_worker(struct work_struct *work)
{
struct sy6982c_charger *cg = container_of(work,
struct sy6982c_charger, usb_work.work);
struct extcon_dev *edev = cg->cable_edev;
enum charger_t charger = USB_TYPE_UNKNOWN_CHARGER;
const char *event[5] = {"UN", "NONE", "USB", "AC", "CDP1.5A"};
/* Determine cable/charger type */
if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_SDP) > 0)
charger = USB_TYPE_USB_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) > 0)
charger = USB_TYPE_AC_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) > 0)
charger = USB_TYPE_CDP_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) == 0)
charger = USB_TYPE_NONE_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) == 0)
charger = USB_TYPE_NONE_CHARGER;
if (charger != USB_TYPE_UNKNOWN_CHARGER) {
dev_info(cg->dev, "receive type-c notifier event: %s...\n",
event[charger]);
cg->usb_charger = charger;
}
}
static int sy6982c_cg_charger_evt_notifier(struct notifier_block *nb,
unsigned long event,
void *ptr)
{
struct sy6982c_charger *cg =
container_of(nb, struct sy6982c_charger, cable_cg_nb);
queue_delayed_work(cg->usb_charger_wq, &cg->usb_work,
msecs_to_jiffies(10));
return NOTIFY_DONE;
}
static void sy6982c_cg_discnt_evt_worker(struct work_struct *work)
{
struct sy6982c_charger *cg = container_of(work,
struct sy6982c_charger, discnt_work.work);
if (extcon_get_cable_state_(cg->cable_edev, EXTCON_USB) == 0) {
dev_info(cg->dev, "receive type-c notifier event: DISCNT...\n");
cg->usb_charger = USB_TYPE_NONE_CHARGER;
}
}
static int sy6982c_cg_discnt_evt_notfier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct sy6982c_charger *cg =
container_of(nb, struct sy6982c_charger, cable_discnt_nb);
queue_delayed_work(cg->usb_charger_wq, &cg->discnt_work,
msecs_to_jiffies(10));
return NOTIFY_DONE;
}
static int sy6982c_cg_init_usb(struct sy6982c_charger *cg)
{
struct device *dev = cg->dev;
int ret;
struct extcon_dev *edev;
if (!cg->extcon)
return -1;
edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(edev)) {
if (PTR_ERR(edev) != -EPROBE_DEFER)
dev_err(dev, "Invalid or missing extcon\n");
return PTR_ERR(edev);
}
cg->usb_charger_wq = alloc_ordered_workqueue("%s",
WQ_MEM_RECLAIM | WQ_FREEZABLE,
"sy6982c-usb-wq");
cg->usb_charger = USB_TYPE_NONE_CHARGER;
/* Register chargers */
INIT_DELAYED_WORK(&cg->usb_work, sy6982c_cg_bc_evt_worker);
cg->cable_cg_nb.notifier_call = sy6982c_cg_charger_evt_notifier;
ret = devm_extcon_register_notifier(dev, edev, EXTCON_CHG_USB_SDP,
&cg->cable_cg_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for SDP\n");
goto __fail;
}
ret = devm_extcon_register_notifier(dev, edev, EXTCON_CHG_USB_DCP,
&cg->cable_cg_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for DCP\n");
goto __fail;
}
ret = devm_extcon_register_notifier(dev, edev, EXTCON_CHG_USB_CDP,
&cg->cable_cg_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for CDP\n");
goto __fail;
}
/* Register discnt usb */
INIT_DELAYED_WORK(&cg->discnt_work, sy6982c_cg_discnt_evt_worker);
cg->cable_discnt_nb.notifier_call = sy6982c_cg_discnt_evt_notfier;
ret = devm_extcon_register_notifier(dev, edev, EXTCON_USB,
&cg->cable_discnt_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for HOST\n");
goto __fail;
}
cg->cable_edev = edev;
schedule_delayed_work(&cg->usb_work, 0);
dev_info(cg->dev, "register extcon evt notifier\n");
return 0;
__fail:
destroy_workqueue(cg->usb_charger_wq);
return ret;
}
static enum power_supply_property sy6982c_usb_props[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_STATUS,
};
static int sy6982c_cg_usb_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct sy6982c_charger *cg = power_supply_get_drvdata(psy);
int online = 0;
int ret = 0;
if (cg->usb_charger != USB_TYPE_UNKNOWN_CHARGER &&
cg->usb_charger != USB_TYPE_NONE_CHARGER)
online = 1;
if (cg->dc_charger != DC_TYPE_NONE_CHARGER)
online = 1;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = online;
dev_dbg(cg->dev, "report online: %d\n", val->intval);
break;
case POWER_SUPPLY_PROP_STATUS:
if (online)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
dev_dbg(cg->dev, "report prop: %d\n", val->intval);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct power_supply_desc sy6982c_usb_desc = {
.name = "sy6982c_usb",
.type = POWER_SUPPLY_TYPE_USB,
.properties = sy6982c_usb_props,
.num_properties = ARRAY_SIZE(sy6982c_usb_props),
.get_property = sy6982c_cg_usb_get_property,
};
static int sy6982c_cg_init_power_supply(struct sy6982c_charger *cg)
{
struct power_supply_config psy_cfg = { .drv_data = cg, };
cg->usb_psy = devm_power_supply_register(cg->dev, &sy6982c_usb_desc,
&psy_cfg);
if (IS_ERR(cg->usb_psy)) {
dev_err(cg->dev, "register usb power supply fail\n");
return PTR_ERR(cg->usb_psy);
}
return 0;
}
#ifdef CONFIG_OF
static int sy6982c_charger_parse_dt(struct sy6982c_charger *cg)
{
struct device *dev = cg->dev;
cg->dc_det_pin = devm_gpiod_get_optional(dev, "dc-det",
GPIOD_IN);
if (!IS_ERR_OR_NULL(cg->dc_det_pin)) {
cg->support_dc_det = true;
} else {
dev_err(dev, "invalid dc det gpio!\n");
cg->support_dc_det = false;
}
return 0;
}
#else
static int sy6982c_charger_parse_dt(struct sy6982c_charger *cg)
{
return -ENODEV;
}
#endif
static enum charger_t sy6982c_charger_get_dc_state(struct sy6982c_charger *cg)
{
return (gpiod_get_value(cg->dc_det_pin)) ?
DC_TYPE_DC_CHARGER : DC_TYPE_NONE_CHARGER;
}
static void sy6982c_charger_dc_det_worker(struct work_struct *work)
{
enum charger_t charger;
struct sy6982c_charger *cg = container_of(work,
struct sy6982c_charger, dc_work.work);
charger = sy6982c_charger_get_dc_state(cg);
if (charger == DC_TYPE_DC_CHARGER)
cg->dc_charger = charger;
else
cg->dc_charger = DC_TYPE_NONE_CHARGER;
rk_send_wakeup_key();
}
static irqreturn_t sy6982c_charger_dc_det_isr(int irq, void *charger)
{
struct sy6982c_charger *cg = (struct sy6982c_charger *)charger;
queue_delayed_work(cg->dc_charger_wq, &cg->dc_work,
msecs_to_jiffies(10));
return IRQ_HANDLED;
}
static int sy6982c_charger_init_dc(struct sy6982c_charger *cg)
{
int ret;
unsigned long irq_flags;
unsigned int dc_det_irq;
if (!cg->support_dc_det)
return 0;
cg->dc_charger_wq = alloc_ordered_workqueue("%s",
WQ_MEM_RECLAIM | WQ_FREEZABLE,
"sy6982c-dc-wq");
if (!cg->dc_charger_wq)
return -EINVAL;
INIT_DELAYED_WORK(&cg->dc_work, sy6982c_charger_dc_det_worker);
cg->dc_charger = DC_TYPE_NONE_CHARGER;
if (gpiod_get_value(cg->dc_det_pin))
cg->dc_charger = DC_TYPE_DC_CHARGER;
else
cg->dc_charger = DC_TYPE_NONE_CHARGER;
irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
dc_det_irq = gpiod_to_irq(cg->dc_det_pin);
ret = devm_request_irq(cg->dev, dc_det_irq, sy6982c_charger_dc_det_isr,
irq_flags, "sy6982c_dc_det", cg);
if (ret != 0) {
dev_err(cg->dev, "sy6982c_dc_det_irq request failed!\n");
return ret;
}
enable_irq_wake(dc_det_irq);
return 0;
}
static int sy6982c_charger_probe(struct platform_device *pdev)
{
struct sy6982c_charger *cg;
int ret;
cg = devm_kzalloc(&pdev->dev, sizeof(*cg), GFP_KERNEL);
if (!cg)
return -ENOMEM;
cg->dev = &pdev->dev;
sy6982c_charger_parse_dt(cg);
sy6982c_charger_init_dc(cg);
cg->extcon = device_property_read_bool(cg->dev, "extcon");
ret = sy6982c_cg_init_usb(cg);
if (ret) {
dev_err(cg->dev, "init usb failed!\n");
return ret;
}
ret = sy6982c_cg_init_power_supply(cg);
if (ret) {
dev_err(cg->dev, "init power supply fail!\n");
return ret;
}
dev_info(cg->dev, "driver registered\n");
return 0;
}
static int sy6982c_charger_remove(struct platform_device *pdev)
{
struct sy6982c_charger *cg = platform_get_drvdata(pdev);
if (cg->usb_charger_wq)
destroy_workqueue(cg->usb_charger_wq);
return 0;
}
static const struct of_device_id sy6982c_charger_match[] = {
{
.compatible = "sy6982c-charger",
},
{},
};
static struct platform_driver sy6982c_charger_driver = {
.probe = sy6982c_charger_probe,
.remove = sy6982c_charger_remove,
.driver = {
.name = "sy6982c-charger",
.of_match_table = sy6982c_charger_match,
},
};
module_platform_driver(sy6982c_charger_driver);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:sy6982c-charger");
MODULE_AUTHOR("chen Shunqing<csq@rock-chips.com>");

View File

@@ -1,419 +0,0 @@
/*
* universal charger driver
*
* Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/extcon.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/power/rk_usbbc.h>
#include <linux/property.h>
#include <linux/workqueue.h>
enum charger_t {
USB_TYPE_UNKNOWN_CHARGER,
USB_TYPE_NONE_CHARGER,
USB_TYPE_USB_CHARGER,
USB_TYPE_AC_CHARGER,
USB_TYPE_CDP_CHARGER,
DC_TYPE_DC_CHARGER,
DC_TYPE_NONE_CHARGER,
};
struct universal_charger {
struct device *dev;
struct power_supply *usb_psy;
struct workqueue_struct *usb_charger_wq;
struct delayed_work usb_work;
struct workqueue_struct *dc_charger_wq;
struct delayed_work dc_work;
struct delayed_work discnt_work;
struct notifier_block cable_cg_nb;
struct notifier_block cable_discnt_nb;
unsigned int bc_event;
enum charger_t usb_charger;
enum charger_t dc_charger;
bool extcon;
struct extcon_dev *cable_edev;
struct gpio_desc *dc_det_pin;
bool support_dc_det;
};
static void universal_cg_bc_evt_worker(struct work_struct *work)
{
struct universal_charger *cg =
container_of(work, struct universal_charger, usb_work.work);
struct extcon_dev *edev = cg->cable_edev;
enum charger_t charger = USB_TYPE_UNKNOWN_CHARGER;
const char *event[5] = {"UN", "NONE", "USB", "AC", "CDP1.5A"};
/* Determine cable/charger type */
if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_SDP) > 0)
charger = USB_TYPE_USB_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) > 0)
charger = USB_TYPE_AC_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) > 0)
charger = USB_TYPE_CDP_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) == 0)
charger = USB_TYPE_NONE_CHARGER;
else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) == 0)
charger = USB_TYPE_NONE_CHARGER;
if (charger != USB_TYPE_UNKNOWN_CHARGER) {
dev_info(cg->dev, "receive usb notifier event: %s...\n",
event[charger]);
cg->usb_charger = charger;
}
}
static int universal_cg_charger_evt_notifier(struct notifier_block *nb,
unsigned long event,
void *ptr)
{
struct universal_charger *cg =
container_of(nb, struct universal_charger, cable_cg_nb);
queue_delayed_work(cg->usb_charger_wq, &cg->usb_work,
msecs_to_jiffies(10));
return NOTIFY_DONE;
}
static void universal_cg_discnt_evt_worker(struct work_struct *work)
{
struct universal_charger *cg = container_of(work,
struct universal_charger, discnt_work.work);
if (extcon_get_cable_state_(cg->cable_edev, EXTCON_USB) == 0) {
dev_info(cg->dev, "receive usb notifier event: DISCNT...\n");
cg->usb_charger = USB_TYPE_NONE_CHARGER;
}
}
static int universal_cg_discnt_evt_notfier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct universal_charger *cg =
container_of(nb, struct universal_charger, cable_discnt_nb);
queue_delayed_work(cg->usb_charger_wq, &cg->discnt_work,
msecs_to_jiffies(10));
return NOTIFY_DONE;
}
static int universal_cg_init_usb(struct universal_charger *cg)
{
struct device *dev = cg->dev;
int ret;
struct extcon_dev *edev;
if (!cg->extcon)
return 0;
edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(edev)) {
if (PTR_ERR(edev) != -EPROBE_DEFER)
dev_err(dev, "Invalid or missing extcon\n");
return PTR_ERR(edev);
}
cg->usb_charger_wq = alloc_ordered_workqueue("%s",
WQ_MEM_RECLAIM | WQ_FREEZABLE,
"universal-usb-wq");
if (!cg->usb_charger_wq)
return -ENOMEM;
cg->usb_charger = USB_TYPE_NONE_CHARGER;
/* Register chargers */
INIT_DELAYED_WORK(&cg->usb_work, universal_cg_bc_evt_worker);
cg->cable_cg_nb.notifier_call = universal_cg_charger_evt_notifier;
ret = devm_extcon_register_notifier(dev, edev, EXTCON_CHG_USB_SDP,
&cg->cable_cg_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for SDP\n");
goto __fail;
}
ret = devm_extcon_register_notifier(dev, edev, EXTCON_CHG_USB_DCP,
&cg->cable_cg_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for DCP\n");
goto __fail;
}
ret = devm_extcon_register_notifier(dev, edev, EXTCON_CHG_USB_CDP,
&cg->cable_cg_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for CDP\n");
goto __fail;
}
/* Register discnt usb */
INIT_DELAYED_WORK(&cg->discnt_work, universal_cg_discnt_evt_worker);
cg->cable_discnt_nb.notifier_call = universal_cg_discnt_evt_notfier;
ret = devm_extcon_register_notifier(dev, edev, EXTCON_USB,
&cg->cable_discnt_nb);
if (ret < 0) {
dev_err(dev, "failed to register notifier for HOST\n");
goto __fail;
}
cg->cable_edev = edev;
schedule_delayed_work(&cg->usb_work, 0);
dev_info(cg->dev, "register extcon evt notifier\n");
return 0;
__fail:
destroy_workqueue(cg->usb_charger_wq);
return ret;
}
static enum power_supply_property universal_usb_props[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_STATUS,
};
static int universal_cg_usb_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct universal_charger *cg = power_supply_get_drvdata(psy);
int online = 0;
int ret = 0;
if (cg->usb_charger != USB_TYPE_UNKNOWN_CHARGER &&
cg->usb_charger != USB_TYPE_NONE_CHARGER)
online = 1;
if (cg->dc_charger != DC_TYPE_NONE_CHARGER)
online = 1;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = online;
dev_dbg(cg->dev, "report online: %d\n", val->intval);
break;
case POWER_SUPPLY_PROP_STATUS:
if (online)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
dev_dbg(cg->dev, "report prop: %d\n", val->intval);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct power_supply_desc universal_usb_desc = {
.name = "universal_usb",
.type = POWER_SUPPLY_TYPE_USB,
.properties = universal_usb_props,
.num_properties = ARRAY_SIZE(universal_usb_props),
.get_property = universal_cg_usb_get_property,
};
static int universal_cg_init_power_supply(struct universal_charger *cg)
{
struct power_supply_config psy_cfg = { .drv_data = cg, };
cg->usb_psy = devm_power_supply_register(cg->dev, &universal_usb_desc,
&psy_cfg);
if (IS_ERR(cg->usb_psy)) {
dev_err(cg->dev, "register usb power supply fail\n");
return PTR_ERR(cg->usb_psy);
}
return 0;
}
#ifdef CONFIG_OF
static int universal_charger_parse_dt(struct universal_charger *cg)
{
struct device *dev = cg->dev;
cg->dc_det_pin = devm_gpiod_get_optional(dev, "dc-det",
GPIOD_IN);
if (!IS_ERR_OR_NULL(cg->dc_det_pin)) {
cg->support_dc_det = true;
} else {
dev_err(dev, "invalid dc det gpio!\n");
cg->support_dc_det = false;
}
return 0;
}
#else
static int universal_charger_parse_dt(struct universal_charger *cg)
{
return -ENODEV;
}
#endif
static enum
charger_t universal_charger_get_dc_state(struct universal_charger *cg)
{
return (gpiod_get_value(cg->dc_det_pin)) ?
DC_TYPE_DC_CHARGER : DC_TYPE_NONE_CHARGER;
}
static void universal_charger_dc_det_worker(struct work_struct *work)
{
enum charger_t charger;
struct universal_charger *cg = container_of(work,
struct universal_charger, dc_work.work);
charger = universal_charger_get_dc_state(cg);
if (charger == DC_TYPE_DC_CHARGER)
cg->dc_charger = charger;
else
cg->dc_charger = DC_TYPE_NONE_CHARGER;
}
static irqreturn_t universal_charger_dc_det_isr(int irq, void *charger)
{
struct universal_charger *cg = (struct universal_charger *)charger;
queue_delayed_work(cg->dc_charger_wq, &cg->dc_work,
msecs_to_jiffies(10));
return IRQ_HANDLED;
}
static int universal_charger_init_dc(struct universal_charger *cg)
{
int ret;
unsigned long irq_flags;
unsigned int dc_det_irq;
if (!cg->support_dc_det)
return 0;
cg->dc_charger_wq = alloc_ordered_workqueue("%s",
WQ_MEM_RECLAIM | WQ_FREEZABLE,
"universal-dc-wq");
if (!cg->dc_charger_wq)
return -ENOMEM;
INIT_DELAYED_WORK(&cg->dc_work, universal_charger_dc_det_worker);
cg->dc_charger = DC_TYPE_NONE_CHARGER;
if (gpiod_get_value(cg->dc_det_pin))
cg->dc_charger = DC_TYPE_DC_CHARGER;
else
cg->dc_charger = DC_TYPE_NONE_CHARGER;
irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
dc_det_irq = gpiod_to_irq(cg->dc_det_pin);
ret = devm_request_irq(cg->dev, dc_det_irq,
universal_charger_dc_det_isr,
irq_flags, "universal_dc_det", cg);
if (ret != 0) {
destroy_workqueue(cg->dc_charger_wq);
dev_err(cg->dev, "universal_dc_det_irq request failed!\n");
return ret;
}
enable_irq_wake(dc_det_irq);
return 0;
}
static int universal_charger_probe(struct platform_device *pdev)
{
struct universal_charger *cg;
int ret;
cg = devm_kzalloc(&pdev->dev, sizeof(*cg), GFP_KERNEL);
if (!cg)
return -ENOMEM;
cg->dev = &pdev->dev;
universal_charger_parse_dt(cg);
ret = universal_charger_init_dc(cg);
if (ret) {
dev_err(cg->dev, "init dc failed!\n");
return ret;
}
cg->extcon = device_property_read_bool(cg->dev, "extcon");
ret = universal_cg_init_usb(cg);
if (ret) {
dev_err(cg->dev, "init usb failed!\n");
goto __init_usb_fail;
}
ret = universal_cg_init_power_supply(cg);
if (ret) {
dev_err(cg->dev, "init power supply fail!\n");
goto ___init_psy_fail;
}
dev_info(cg->dev, "driver registered\n");
return 0;
___init_psy_fail:
if (cg->usb_charger_wq)
destroy_workqueue(cg->usb_charger_wq);
__init_usb_fail:
if (cg->dc_charger_wq)
destroy_workqueue(cg->dc_charger_wq);
return ret;
}
static int universal_charger_remove(struct platform_device *pdev)
{
struct universal_charger *cg = platform_get_drvdata(pdev);
if (cg->usb_charger_wq)
destroy_workqueue(cg->usb_charger_wq);
if (cg->dc_charger_wq)
destroy_workqueue(cg->dc_charger_wq);
return 0;
}
static const struct of_device_id universal_charger_match[] = {
{
.compatible = "universal-charger",
},
{},
};
static struct platform_driver universal_charger_driver = {
.probe = universal_charger_probe,
.remove = universal_charger_remove,
.driver = {
.name = "universal-charger",
.of_match_table = universal_charger_match,
},
};
module_platform_driver(universal_charger_driver);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:universal-charger");
MODULE_AUTHOR("chen Shunqing<csq@rock-chips.com>");

View File

@@ -5,14 +5,3 @@ menuconfig ROCKCHIP_DVBM
depends on ARCH_ROCKCHIP
help
rockchip dvbm module.
if ROCKCHIP_DVBM
config ROCKCHIP_DVBM_PROC_FS
bool "enable dvbm procfs"
depends on PROC_FS
default y
help
rockchip dvbm procfs.
endif

View File

@@ -7,17 +7,10 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/proc_fs.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <soc/rockchip/rockchip_dvbm.h>
#include "rockchip_dvbm.h"
#define RK_DVBM "rk_dvbm"
unsigned int dvbm_debug;
@@ -27,9 +20,6 @@ MODULE_PARM_DESC(dvbm_debug, "bit switch for dvbm debug information");
static struct dvbm_ctx *g_ctx;
#define DVBM_DEBUG 0x00000001
#define DVBM_DEBUG_IRQ 0x00000002
#define DVBM_DEBUG_REG 0x00000004
#define DVBM_DEBUG_DUMP 0x00000008
#define DVBM_DEBUG_FRM 0x00000010
#define dvbm_debug(fmt, args...) \
@@ -38,106 +28,45 @@ static struct dvbm_ctx *g_ctx;
pr_info(fmt, ##args); \
} while (0)
#define dvbm_debug_reg(fmt, args...) \
do { \
if (unlikely(dvbm_debug & (DVBM_DEBUG_REG))) \
pr_info(fmt, ##args); \
} while (0)
#define dvbm_debug_irq(fmt, args...) \
do { \
if (unlikely(dvbm_debug & (DVBM_DEBUG_IRQ))) \
pr_info(fmt, ##args); \
} while (0)
#define dvbm_debug_dump(fmt, args...) \
do { \
if (unlikely(dvbm_debug & (DVBM_DEBUG_DUMP))) \
pr_info(fmt, ##args); \
} while (0)
#define dvbm_debug_frm(fmt, args...) \
do { \
if (unlikely(dvbm_debug & (DVBM_DEBUG_FRM))) \
pr_info(fmt, ##args); \
} while (0)
#define dvbm_err(fmt, args...) \
pr_err(fmt, ##args)
#define dvbm_err(fmt, args...) \
pr_err("%s:%d: " fmt, __func__, __LINE__, ##args)
enum dvbm_flow {
ISP_CFG = 1,
ISP_CONNECT = 2,
VEPU_CFG = 3,
VEPU_CONNECT = 4,
};
/* dvbm status reg bit value define */
#define BUF_OVERFLOW BIT(0)
#define RESYNC_FINISH BIT(1)
#define ISP_CNCT_TIMEOUT BIT(2)
#define VEPU_CNCT_TIMEOUT BIT(3)
#define VEPU_HANDSHAKE_TIMEOUT BIT(4)
#define ISP_CNCT BIT(5)
#define ISP_DISCNCT BIT(6)
#define VEPU_CNCT BIT(7)
#define VEPU_DISCNCT BIT(8)
/* dvbm reg addr define */
#define DVBM_VERSION 0x0
#define DVBM_ISP_CNCT 0x4
#define DVBM_VEPU_CNCT 0x8
/* cfg regs */
#define DVBM_CFG 0xC
#define DVBM_WDG_CFG0 0x10
#define DVBM_WDG_CFG1 0x14
#define DVBM_WDG_CFG2 0x18
/* interrupt regs */
#define DVBM_INT_EN 0x1c
#define DVBM_INT_MSK 0x20
#define DVBM_INT_CLR 0x24
#define DVBM_INT_ST 0x28
/* addr regs */
#define DVBM_YBUF_BOT 0x2c
#define DVBM_YBUF_TOP 0x30
#define DVBM_YBUF_SADR 0x34
#define DVBM_YBUF_LSTD 0x38
#define DVBM_YBUF_FSTD 0x3c
#define DVBM_CBUF_BOT 0x40
#define DVBM_CBUF_TOP 0x44
#define DVBM_CBUF_SADR 0x48
#define DVBM_CBUF_LSTD 0x4c
#define DVBM_CBUF_FSTD 0x50
#define DVBM_AFUL_THDY 0x54
#define DVBM_AFUL_THDC 0x58
#define DVBM_OVFL_THDY 0x5c
#define DVBM_OVFL_THDC 0x60
/* status regs */
#define DVBM_ST 0x80
#define DVBM_OVFL_ST 0x84
#define DVBM_REG_OFFSET 0x2c
#define SOFT_DVBM 1
#define UPDATE_LINE_CNT 0
static void rk_dvbm_set_reg(struct dvbm_ctx *ctx, u32 offset, u32 val)
{
if (!SOFT_DVBM) {
dvbm_debug_reg("write reg[%d] 0x%x = 0x%08x\n", offset >> 2, offset, val);
writel(val, ctx->reg_base + offset);
}
}
#define DVBM_CHANNEL_NUM (3)
static u32 rk_dvbm_read_reg(struct dvbm_ctx *ctx, u32 offset)
{
u32 val = 0;
struct dvbm_ctx {
struct device *dev;
if (!SOFT_DVBM) {
val = readl(ctx->reg_base + offset);
dvbm_debug_reg("read reg[%d] 0x%x = 0x%08x\n", offset >> 2, offset, val);
}
return val;
}
u32 isp_connet;
u32 vepu_connet;
/* vepu infos */
struct dvbm_port port_vepu;
atomic_t vepu_link;
struct dvbm_cb vepu_cb;
struct dvbm_addr_cfg vepu_cfg;
/* isp infos */
struct dvbm_port port_isp;
struct dvbm_cb isp_cb;
struct dvbm_isp_cfg_t isp_cfg[DVBM_CHANNEL_NUM];
struct dvbm_addr_cfg dvbm_addr[DVBM_CHANNEL_NUM];
u32 chan_id;
struct dvbm_isp_frm_info isp_frm_info;
atomic_t isp_link;
u32 isp_max_lcnt;
u32 isp_frm_start;
u32 isp_frm_end;
ktime_t isp_frm_time;
u32 wrap_line;
};
static struct dvbm_ctx *port_to_ctx(struct dvbm_port *port)
{
@@ -158,39 +87,12 @@ static void dvbm2enc_callback(struct dvbm_ctx *ctx, enum dvbm_cb_event event, vo
struct dvbm_cb *callback = &ctx->vepu_cb;
dvbm_callback cb = callback->cb;
if (!ctx->port_vepu.linked)
if (!cb) {
dvbm_err("vepu callback is null\n");
return;
if (cb)
cb(callback->ctx, event, arg);
}
}
static void rk_dvbm_dump_regs(struct dvbm_ctx *ctx)
{
u32 start = ctx->dump_s;//0x80;
u32 end = ctx->dump_e;//0xb8;
u32 i;
dvbm_debug_dump("=== %s ===\n", __func__);
for (i = start; i <= end; i += 4)
dvbm_debug_dump("reg[0x%0x] = 0x%08x\n", i, readl(ctx->reg_base + i));
dvbm_debug_dump("=== %s ===\n", __func__);
}
static int rk_dvbm_clk_on(struct dvbm_ctx *ctx)
{
int ret = 0;
if (ctx->clk)
ret = clk_prepare_enable(ctx->clk);
if (ret)
dev_err(ctx->dev, "clk on failed\n");
return ret;
}
static int rk_dvbm_clk_off(struct dvbm_ctx *ctx)
{
if (ctx->clk)
clk_disable_unprepare(ctx->clk);
return 0;
cb(callback->ctx, event, arg);
}
static void init_isp_infos(struct dvbm_ctx *ctx)
@@ -222,84 +124,6 @@ static void rk_dvbm_update_isp_frm_info(struct dvbm_ctx *ctx, u32 line_cnt)
#endif
}
static int rk_dvbm_setup_iobuf(struct dvbm_ctx *ctx)
{
u32 *data;
u32 i;
struct rk_dvbm_base *addr_base = &ctx->regs.addr_base;
struct dvbm_isp_cfg_t *cfg = &ctx->isp_cfg;
addr_base->ybuf_bot = cfg->dma_addr + cfg->ybuf_bot;
addr_base->ybuf_top = cfg->dma_addr + cfg->ybuf_top;
addr_base->ybuf_sadr = cfg->dma_addr + cfg->ybuf_bot;
addr_base->ybuf_fstd = cfg->ybuf_fstd;
addr_base->ybuf_lstd = cfg->ybuf_lstd;
addr_base->cbuf_bot = cfg->dma_addr + cfg->cbuf_bot;
addr_base->cbuf_top = cfg->dma_addr + cfg->cbuf_top;
addr_base->cbuf_sadr = cfg->dma_addr + cfg->cbuf_bot;
addr_base->cbuf_fstd = cfg->cbuf_fstd;
addr_base->cbuf_lstd = cfg->cbuf_lstd;
addr_base->aful_thdy = cfg->ybuf_lstd;
addr_base->aful_thdc = cfg->ybuf_lstd;
addr_base->oful_thdy = cfg->ybuf_lstd;
addr_base->oful_thdc = cfg->ybuf_lstd;
ctx->isp_max_lcnt = cfg->ybuf_fstd / cfg->ybuf_lstd;
ctx->wrap_line = (cfg->ybuf_top - cfg->ybuf_bot) / cfg->ybuf_lstd;
ctx->isp_frm_info.frame_cnt = 0;
ctx->isp_frm_info.line_cnt = 0;
ctx->isp_frm_info.max_line_cnt = ALIGN(ctx->isp_max_lcnt, 32);
ctx->isp_frm_info.wrap_line = ctx->wrap_line;
dvbm_debug("dma_addr %pad y_lstd %d y_fstd %d\n",
&cfg->dma_addr, cfg->ybuf_lstd, cfg->ybuf_fstd);
dvbm_debug("ybot 0x%x top 0x%x cbuf bot 0x%x top 0x%x\n",
addr_base->ybuf_bot, addr_base->ybuf_top,
addr_base->cbuf_bot, addr_base->cbuf_top);
data = (u32 *)addr_base;
for (i = 0; i < sizeof(struct rk_dvbm_base) / sizeof(u32); i++)
rk_dvbm_set_reg(ctx, i * sizeof(u32) + DVBM_REG_OFFSET, data[i]);
for (i = 1; i < 65536; i++)
if (!((addr_base->ybuf_fstd * i) % (cfg->ybuf_top - cfg->ybuf_bot)))
break;
ctx->loopcnt = i;
return 0;
}
static void rk_dvbm_reg_init(struct dvbm_ctx *ctx)
{
struct rk_dvbm_regs *reg = &ctx->regs;
u32 *val = (u32 *)reg;
reg->int_en.buf_ovfl = 1;
reg->int_en.isp_cnct = 1;
reg->int_en.vepu_cnct = 1;
reg->int_en.vepu_discnct = 1;
reg->int_en.isp_discnct = 1;
reg->int_en.resync_finish = 1;
reg->int_en.isp_cnct_timeout = 1;
reg->int_en.vepu_cnct_timeout = 1;
reg->int_en.vepu_handshake_timeout = 1;
reg->dvbm_cfg.fmt = 0;
reg->dvbm_cfg.auto_resyn = 0;
reg->dvbm_cfg.ignore_vepu_cnct_ack = 0;
reg->dvbm_cfg.start_point_after_vepu_cnct = 0;
reg->wdg_cfg0.wdg_isp_cnct_timeout = 0xfffff;
reg->wdg_cfg1.wdg_vepu_cnct_timeout = 0xfffff;
reg->wdg_cfg2.wdg_vepu_handshake_timeout = 0xfffff;
rk_dvbm_set_reg(ctx, DVBM_WDG_CFG0, val[DVBM_WDG_CFG0 >> 2]);
rk_dvbm_set_reg(ctx, DVBM_WDG_CFG1, val[DVBM_WDG_CFG1 >> 2]);
rk_dvbm_set_reg(ctx, DVBM_WDG_CFG2, val[DVBM_WDG_CFG2 >> 2]);
rk_dvbm_set_reg(ctx, DVBM_CFG, val[DVBM_CFG >> 2]);
rk_dvbm_set_reg(ctx, DVBM_INT_EN, val[DVBM_INT_EN >> 2]);
}
struct dvbm_port *rk_dvbm_get_port(struct platform_device *pdev,
enum dvbm_port_dir dir)
{
@@ -329,18 +153,17 @@ int rk_dvbm_put(struct dvbm_port *port)
return -EINVAL;
ctx = port_to_ctx(port);
if (!ctx)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL(rk_dvbm_put);
int rk_dvbm_link(struct dvbm_port *port)
int rk_dvbm_link(struct dvbm_port *port, int id)
{
struct dvbm_ctx *ctx;
enum dvbm_port_dir dir;
struct rk_dvbm_regs *reg;
int ret = 0;
if (WARN_ON(!port))
@@ -348,59 +171,40 @@ int rk_dvbm_link(struct dvbm_port *port)
ctx = port_to_ctx(port);
dir = port->dir;
reg = &ctx->regs;
if (dir == DVBM_ISP_PORT) {
if (port->linked) {
rk_dvbm_unlink(port);
udelay(5);
}
reg->isp_cnct.isp_cnct = 1;
rk_dvbm_set_reg(ctx, DVBM_ISP_CNCT, 0x1);
if (id >= DVBM_CHANNEL_NUM)
dvbm_err("id %d is invalid\n", id);
dvbm2enc_callback(ctx, DVBM_ISP_REQ_CONNECT, &id);
} else if (dir == DVBM_VEPU_PORT) {
if (!port->linked) {
reg->vepu_cnct.vepu_cnct = 1;
rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0x1);
}
port->linked = 1;
dvbm_debug_dump("=== vepu link ===\n");
rk_dvbm_dump_regs(ctx);
dvbm_debug_dump("=== vepu link ===\n");
}
dvbm_debug("%s connect frm_cnt[%d : %d]\n",
dir == DVBM_ISP_PORT ? "isp" : "vepu",
dvbm_debug("%s %d connect frm_cnt[%d : %d]\n",
dir == DVBM_ISP_PORT ? "isp" : "vepu", id,
ctx->isp_frm_start, ctx->isp_frm_end);
return ret;
}
EXPORT_SYMBOL(rk_dvbm_link);
int rk_dvbm_unlink(struct dvbm_port *port)
int rk_dvbm_unlink(struct dvbm_port *port, int id)
{
struct dvbm_ctx *ctx;
enum dvbm_port_dir dir;
struct rk_dvbm_regs *reg;
if (WARN_ON(!port))
return -EINVAL;
ctx = port_to_ctx(port);
dir = port->dir;
reg = &ctx->regs;
if (dir == DVBM_ISP_PORT) {
reg->isp_cnct.isp_cnct = 0;
rk_dvbm_set_reg(ctx, DVBM_ISP_CNCT, 0);
} else if (dir == DVBM_VEPU_PORT) {
reg->vepu_cnct.vepu_cnct = 0;
port->linked = 0;
rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0);
if (!ctx->regs.dvbm_cfg.auto_resyn) {
u32 connect = 0;
if (id >= DVBM_CHANNEL_NUM)
dvbm_err("id %d is invalid\n", id);
dvbm2enc_callback(ctx, DVBM_VEPU_REQ_CONNECT, &connect);
}
dvbm2enc_callback(ctx, DVBM_ISP_REQ_DISCONNECT, &id);
} else if (dir == DVBM_VEPU_PORT) {
}
dvbm_debug("%s disconnect\n", dir == DVBM_ISP_PORT ? "isp" : "vepu");
@@ -430,27 +234,9 @@ int rk_dvbm_set_cb(struct dvbm_port *port, struct dvbm_cb *cb)
}
EXPORT_SYMBOL(rk_dvbm_set_cb);
static void rk_dvbm_update_next_adr(struct dvbm_ctx *ctx)
{
u32 frame_cnt = ctx->isp_frm_start;
struct dvbm_isp_cfg_t *isp_cfg = &ctx->isp_cfg;
struct dvbm_addr_cfg *vepu_cfg = &ctx->vepu_cfg;
u32 y_wrap_size = isp_cfg->ybuf_top - isp_cfg->ybuf_bot;
u32 c_wrap_size = isp_cfg->cbuf_top - isp_cfg->cbuf_bot;
u32 s_off;
frame_cnt = (frame_cnt + 1) % (ctx->loopcnt);
s_off = (frame_cnt * isp_cfg->ybuf_fstd) % y_wrap_size;
vepu_cfg->ybuf_sadr = isp_cfg->dma_addr + isp_cfg->ybuf_bot + s_off;
s_off = (frame_cnt * isp_cfg->cbuf_fstd) % c_wrap_size;
vepu_cfg->cbuf_sadr = isp_cfg->dma_addr + isp_cfg->cbuf_bot + s_off;
}
int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
{
struct dvbm_ctx *ctx;
struct rk_dvbm_regs *reg;
if ((cmd < DVBM_ISP_CMD_BASE) || (cmd > DVBM_VEPU_CMD_BUTT)) {
dvbm_err("%s input cmd invalid\n", __func__);
@@ -458,28 +244,43 @@ int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
}
ctx = port_to_ctx(port);
reg = &ctx->regs;
switch (cmd) {
case DVBM_ISP_SET_CFG: {
struct dvbm_isp_cfg_t *cfg = (struct dvbm_isp_cfg_t *)arg;
struct dvbm_addr_cfg *dvbm_adr;
u32 chan_id = cfg->chan_id;
memcpy(&ctx->isp_cfg, cfg, sizeof(struct dvbm_isp_cfg_t));
rk_dvbm_setup_iobuf(ctx);
if (chan_id >= DVBM_CHANNEL_NUM) {
dvbm_err("%s cmd %d chan id %d is invalid\n", __func__, cmd, chan_id);
return -EINVAL;
}
memcpy(&ctx->isp_cfg[chan_id], cfg, sizeof(struct dvbm_isp_cfg_t));
init_isp_infos(ctx);
rk_dvbm_update_next_adr(ctx);
dvbm_adr = &ctx->dvbm_addr[chan_id];
dvbm_adr->chan_id = chan_id;
dvbm_adr->ybuf_bot = cfg->dma_addr + cfg->ybuf_bot;
dvbm_adr->ybuf_top = cfg->dma_addr + cfg->ybuf_top;
dvbm_adr->ybuf_sadr = cfg->dma_addr + cfg->ybuf_bot;
dvbm_adr->cbuf_bot = cfg->dma_addr + cfg->cbuf_bot;
dvbm_adr->cbuf_top = cfg->dma_addr + cfg->cbuf_top;
dvbm_adr->cbuf_sadr = cfg->dma_addr + cfg->cbuf_bot;
dvbm2enc_callback(ctx, DVBM_ISP_SET_DVBM_CFG, cfg);
} break;
case DVBM_ISP_FRM_START: {
dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_FRM_STR, arg);
rk_dvbm_update_isp_frm_info(ctx, 0);
rk_dvbm_show_time(ctx);
} break;
case DVBM_ISP_FRM_END: {
u32 line_cnt = ctx->isp_max_lcnt;
dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_FRM_END, arg);
ctx->isp_frm_end = *(u32 *)arg;
/* wrap frame_cnt 0 - 255 */
ctx->isp_frm_info.frame_cnt = (ctx->isp_frm_start + 1) % 256;
rk_dvbm_update_next_adr(ctx);
rk_dvbm_update_isp_frm_info(ctx, line_cnt);
ctx->isp_frm_start++;
dvbm_debug("isp frame end[%d : %d]\n", ctx->isp_frm_start, ctx->isp_frm_end);
@@ -504,38 +305,14 @@ int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
} break;
case DVBM_VEPU_GET_ADR: {
struct dvbm_addr_cfg *dvbm_adr = (struct dvbm_addr_cfg *)arg;
struct rk_dvbm_base *addr_base = &reg->addr_base;
u32 chan_id = dvbm_adr->chan_id;
dvbm_adr->ybuf_top = addr_base->ybuf_top;
dvbm_adr->ybuf_bot = addr_base->ybuf_bot;
dvbm_adr->cbuf_top = addr_base->cbuf_top;
dvbm_adr->cbuf_bot = addr_base->cbuf_bot;
dvbm_adr->cbuf_sadr = ctx->vepu_cfg.cbuf_sadr;
dvbm_adr->ybuf_sadr = ctx->vepu_cfg.ybuf_sadr;
dvbm_adr->overflow = ctx->isp_frm_info.line_cnt >= ctx->wrap_line;
dvbm_adr->frame_id = ctx->isp_frm_info.frame_cnt;
dvbm_adr->line_cnt = ctx->isp_frm_info.line_cnt;
} break;
case DVBM_VEPU_GET_FRAME_INFO: {
memcpy(arg, &ctx->isp_frm_info, sizeof(struct dvbm_isp_frm_info));
} break;
case DVBM_VEPU_SET_RESYNC: {
reg->dvbm_cfg.auto_resyn = *(u32 *)arg;
dev_info(ctx->dev, "change resync %s\n",
reg->dvbm_cfg.auto_resyn ? "auto" : "soft");
rk_dvbm_set_reg(ctx, DVBM_CFG, ((u32 *)&reg->dvbm_cfg)[0]);
} break;
case DVBM_VEPU_SET_CFG: {
struct dvbm_vepu_cfg *cfg = (struct dvbm_vepu_cfg *)arg;
if (chan_id >= DVBM_CHANNEL_NUM) {
dvbm_err("%s cmd %d chan id %d is invalid\n", __func__, cmd, chan_id);
return -EINVAL;
}
reg->dvbm_cfg.auto_resyn = cfg->auto_resyn;
reg->dvbm_cfg.ignore_vepu_cnct_ack = cfg->ignore_vepu_cnct_ack;
reg->dvbm_cfg.start_point_after_vepu_cnct = cfg->start_point_after_vepu_cnct;
rk_dvbm_set_reg(ctx, DVBM_CFG, ((u32 *)&reg->dvbm_cfg)[0]);
} break;
case DVBM_VEPU_DUMP_REGS: {
rk_dvbm_dump_regs(ctx);
*dvbm_adr = ctx->dvbm_addr[chan_id];
} break;
default: {
} break;
@@ -545,163 +322,27 @@ int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
}
EXPORT_SYMBOL(rk_dvbm_ctrl);
static void dvbm_check_irq(struct dvbm_ctx *ctx)
{
u32 irq_st = ctx->irq_status;
u32 cur_st = ctx->dvbm_status;
if (irq_st & ISP_CNCT) {
dvbm_debug_irq("%s isp connect success! st 0x%08x\n",
__func__, cur_st);
ctx->port_isp.linked = 1;
}
if (irq_st & ISP_DISCNCT) {
dvbm_debug_irq("%s isp disconnect success!\n", __func__);
ctx->port_isp.linked = 0;
}
if (irq_st & VEPU_CNCT) {
dvbm_debug_irq("%s vepu connect success! st 0x%08x\n",
__func__, cur_st);
ctx->port_vepu.linked = 1;
}
if (irq_st & VEPU_DISCNCT) {
dvbm_debug_irq("%s vepu disconnect success! st 0x%08x\n", __func__, cur_st);
ctx->port_vepu.linked = 0;
}
if (irq_st & BUF_OVERFLOW) {
dvbm_debug_irq("%s buf overflow st 0x%08x auto_resync %d ignore %d\n",
__func__, cur_st, ctx->regs.dvbm_cfg.auto_resyn, ctx->ignore_ovfl);
if (!ctx->regs.dvbm_cfg.auto_resyn && !ctx->ignore_ovfl)
rk_dvbm_unlink(&ctx->port_vepu);
}
if (irq_st & (ISP_CNCT_TIMEOUT | VEPU_CNCT_TIMEOUT))
rk_dvbm_dump_regs(ctx);
}
static irqreturn_t rk_dvbm_irq(int irq, void *param)
{
struct dvbm_ctx *ctx = param;
u32 irq_st = 0;
u32 cur_st = 0;
if (ctx->reg_base) {
/* read irq st */
irq_st = rk_dvbm_read_reg(ctx, DVBM_INT_ST);
cur_st = rk_dvbm_read_reg(ctx, DVBM_ST);
if (irq_st & BUF_OVERFLOW) {
dvbm_debug_dump("=== dvbm overflow! dump reg st: 0x%08x===\n", irq_st);
rk_dvbm_dump_regs(ctx);
dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_DUMP, NULL);
dvbm_debug_dump("=== dvbm overflow! dump reg end===\n");
}
/* clr irq */
rk_dvbm_set_reg(ctx, DVBM_INT_CLR, irq_st);
rk_dvbm_set_reg(ctx, DVBM_INT_ST, 0);
}
ctx->irq_status = irq_st;
ctx->dvbm_status = cur_st;
dvbm_debug_irq("%s irq status 0x%08x\n", __func__, irq_st);
return IRQ_WAKE_THREAD;
}
static irqreturn_t rk_dvbm_isr(int irq, void *param)
{
struct dvbm_ctx *ctx = param;
dvbm_check_irq(ctx);
return IRQ_HANDLED;
}
static int rk_dvbm_probe(struct platform_device *pdev)
{
int ret;
struct dvbm_ctx *ctx = NULL;
struct device *dev = &pdev->dev;
struct resource *res = NULL;
dev_info(dev, "probe start\n");
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
dev_info(dev, "dvbm ctx %p\n", ctx);
ctx->dev = dev;
atomic_set(&ctx->isp_ref, 0);
atomic_set(&ctx->vepu_ref, 0);
ctx->port_isp.dir = DVBM_ISP_PORT;
ctx->port_vepu.dir = DVBM_VEPU_PORT;
platform_set_drvdata(pdev, ctx);
pm_runtime_enable(dev);
/* get irq */
ctx->irq = platform_get_irq(pdev, 0);
if (ctx->irq < 0) {
dev_err(&pdev->dev, "no interrupt resource found\n");
ret = -ENODEV;
goto failed;
}
/* get mem resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no memory resource defined\n");
ret = -ENODEV;
goto failed;
}
ctx->reg_base = devm_ioremap_resource(dev, res);
if (IS_ERR_OR_NULL(ctx->reg_base)) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
ret = -ENODEV;
goto failed;
}
ctx->clk = devm_clk_get(ctx->dev, "clk_core");
if (IS_ERR_OR_NULL(ctx->clk)) {
dev_err(dev, "clk_get failed for resource %pR\n", res);
ret = -ENODEV;
goto failed;
}
ctx->rst = devm_reset_control_get(ctx->dev, "dvbm_rst");
if (IS_ERR_OR_NULL(ctx->rst)) {
dev_err(dev, "clk_rst failed for resource %pR\n", res);
ret = -ENODEV;
goto failed;
}
if (!SOFT_DVBM) {
ret = pm_runtime_get_sync(dev);
if (ret)
dev_err(dev, "pm get failed!\n");
ret = rk_dvbm_clk_on(ctx);
if (ret)
goto failed;
}
g_ctx = ctx;
rk_dvbm_reg_init(ctx);
ctx->ignore_ovfl = 1;
ctx->dump_s = 0x80;
ctx->dump_e = 0xb8;
ret = devm_request_threaded_irq(dev, ctx->irq,
rk_dvbm_irq, rk_dvbm_isr,
IRQF_ONESHOT, dev_name(dev), ctx);
if (ret) {
dev_err(dev, "register interrupter failed\n");
goto failed;
}
dev_info(dev, "probe success\n");
return 0;
failed:
pm_runtime_disable(dev);
return ret;
}
static int rk_dvbm_remove(struct platform_device *pdev)
@@ -709,11 +350,6 @@ static int rk_dvbm_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
dev_info(dev, "remove device\n");
if (!SOFT_DVBM) {
rk_dvbm_clk_off(g_ctx);
pm_runtime_put(dev);
}
pm_runtime_disable(dev);
return 0;
}

View File

@@ -1,214 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __ROCKCHIP_DVBM_H__
#define __ROCKCHIP_DVBM_H__
#include <linux/clk.h>
#include <linux/reset.h>
struct rk_dvbm_base {
/* 0x2c */
u32 ybuf_bot;
/* 0x30 */
u32 ybuf_top;
/* 0x34 */
u32 ybuf_sadr;
/* 0x38 */
u32 ybuf_lstd;
/* 0x3c */
u32 ybuf_fstd;
/* 0x40 */
u32 cbuf_bot;
/* 0x44 */
u32 cbuf_top;
/* 0x48 */
u32 cbuf_sadr;
/* 0x4c */
u32 cbuf_lstd;
/* 0x50 */
u32 cbuf_fstd;
/* 0x54 */
u32 aful_thdy;
/* 0x58 */
u32 aful_thdc;
/* 0x5c */
u32 oful_thdy;
/* 0x60 */
u32 oful_thdc;
};
struct rk_dvbm_regs {
/* 0x0 */
u32 version;
/* 0x4 */
struct {
u32 isp_cnct : 1;
u32 reserved : 31;
} isp_cnct;
/* 0x8 */
struct {
u32 vepu_cnct : 1;
u32 reserved : 31;
} vepu_cnct;
/* 0xc */
struct {
u32 auto_resyn : 1;
u32 ignore_vepu_cnct_ack : 1;
/*
* 1b0 : the current ISP frame
* 1b1 : the next ISP frame
*/
u32 start_point_after_vepu_cnct : 1;
u32 reserved0 : 5;
/* only support yuv420sp 4'h0 */
u32 fmt : 4;
u32 reserved1 : 20;
} dvbm_cfg;
/* 0x10 */
struct {
u32 wdg_isp_cnct_timeout : 22;
u32 reserved : 10;
} wdg_cfg0;
/* 0x14 */
struct {
u32 wdg_vepu_cnct_timeout : 22;
u32 reserved : 10;
} wdg_cfg1;
/* 0x18 */
struct {
u32 wdg_vepu_handshake_timeout : 22;
u32 reserved : 10;
} wdg_cfg2;
/* 0x1c */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_en;
/* 0x20 */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_msk;
/* 0x24 */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_clr;
/* 0x28 */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_st;
struct rk_dvbm_base addr_base;
/* 0x64 - 0x7c */
u32 reserved[7];
/* 0x80 */
struct {
u32 isp_connection : 1;
u32 vepu_connection : 1;
u32 resynchronization : 1;
u32 y_buf_ovfl : 1;
u32 c_buf_ovfl : 1;
u32 reserved : 27;
} dvbm_st;
/* 0x84 */
u32 ovfl_st;
};
struct dvbm_ctx {
struct clk *clk;
struct device *dev;
void __iomem *reg_base;
struct rk_dvbm_regs regs;
struct reset_control *rst;
u32 isp_connet;
u32 vepu_connet;
u32 buf_overflow;
u32 irq_status;
u32 dvbm_status;
int irq;
/* vepu infos */
struct dvbm_port port_vepu;
atomic_t vepu_ref;
atomic_t vepu_link;
struct dvbm_cb vepu_cb;
struct dvbm_addr_cfg vepu_cfg;
/* isp infos */
struct dvbm_port port_isp;
struct dvbm_cb isp_cb;
struct dvbm_isp_cfg_t isp_cfg;
struct dvbm_isp_frm_info isp_frm_info;
atomic_t isp_link;
atomic_t isp_ref;
u32 isp_max_lcnt;
u32 isp_frm_start;
u32 isp_frm_end;
ktime_t isp_frm_time;
u32 wrap_line;
/* debug infos */
u32 dump_s;
u32 dump_e;
u32 ignore_ovfl;
u32 loopcnt;
};
#endif

View File

@@ -2239,7 +2239,10 @@ int mpp_dev_probe(struct mpp_dev *mpp,
if (IS_ERR(mpp->iommu_info)) {
dev_err(dev, "failed to attach iommu\n");
mpp->iommu_info = NULL;
} else {
mpp->iommu_info->queue = mpp->queue;
}
if (mpp->hw_ops->init) {
ret = mpp->hw_ops->init(mpp);
if (ret)

View File

@@ -507,6 +507,9 @@ struct mpp_taskqueue {
u32 core_id_max;
u32 core_count;
unsigned long dev_active_flags;
/* for devices which share iommu, record last attach device */
struct mpp_iommu_info *last_iommu_info;
};
struct mpp_reset_group {
@@ -547,6 +550,9 @@ struct mpp_service {
/* global timing record flag */
u32 timing_en;
u32 load_interval;
/* bit mask for iommu shared */
u32 iommu_shared_mask;
};
/*

View File

@@ -17,6 +17,7 @@
#include <linux/kref.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#ifdef CONFIG_ARM_DMA_USE_IOMMU
#include <asm/dma-iommu.h>
@@ -451,9 +452,19 @@ int mpp_iommu_detach(struct mpp_iommu_info *info)
int mpp_iommu_attach(struct mpp_iommu_info *info)
{
struct mpp_iommu_info *last_info;
if (!info)
return 0;
/* if device changed, detach last first */
last_info = info->queue->last_iommu_info;
if (info->shared && last_info && last_info->shared
&& (info->dev != last_info->dev)) {
iommu_detach_group(last_info->domain, last_info->group);
}
info->queue->last_iommu_info = info;
if (info->domain == iommu_get_domain_for_dev(info->dev))
return 0;
@@ -561,6 +572,15 @@ mpp_iommu_probe(struct device *dev)
info->irq = platform_get_irq(pdev, 0);
info->got_irq = (info->irq < 0) ? false : true;
/* get shared flag, if true detach */
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
struct platform_driver *drv = to_platform_driver(dev->driver);
info->shared = drv->driver_managed_dma;
if (info->shared)
iommu_detach_group(info->domain, info->group);
}
return info;
err_put_group:
@@ -578,6 +598,10 @@ int mpp_iommu_remove(struct mpp_iommu_info *info)
if (!info)
return 0;
/* if iommu shared, ensure current device's domain, then remove correctly */
if (info->shared)
mpp_iommu_attach(info);
iommu_group_put(info->group);
platform_device_put(info->pdev);

View File

@@ -102,6 +102,9 @@ struct mpp_iommu_info {
int irq;
int got_irq;
/* flag for mark iommu whether shared */
bool shared;
struct mpp_taskqueue *queue;
};
struct mpp_dma_session *

View File

@@ -100,6 +100,9 @@ static int mpp_add_driver(struct mpp_service *srv,
&srv->grf_infos[type],
grf_name);
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
driver->driver_managed_dma = (srv->iommu_shared_mask & BIT(type)) ? true : false;
ret = platform_driver_register(driver);
if (ret)
return ret;
@@ -444,6 +447,9 @@ static int mpp_service_probe(struct platform_device *pdev)
}
}
of_property_read_u32(np, "rockchip,iommu-shared-mask",
&srv->iommu_shared_mask);
ret = mpp_register_service(srv, MPP_SERVICE_NAME);
if (ret) {
dev_err(dev, "register %s device\n", MPP_SERVICE_NAME);

View File

@@ -132,6 +132,14 @@
#define m_RGA2_STATUS1_SW_RGA_STA (0x1 << 0)
/*RGA_INT*/
#define m_RGA2_INT_FBCIN_DEC_ERROR_CLEAR (1 << 24)
#define m_RGA2_INT_FBCIN_DEC_ERROR_EN (1 << 23)
#define m_RGA2_INT_FBCIN_DEC_ERROR (1 << 22)
#define m_RGA2_INT_PREFETCH_TH_INTR (1 << 21)
#define m_RGA2_INT_PRE_TH_CLEAR (1 << 20)
#define m_RGA2_INT_SCL_ERROR_CLEAR (1 << 19)
#define m_RGA2_INT_SCL_ERROR_EN (1 << 18)
#define m_RGA2_INT_SCL_ERROR_INTR (1 << 17)
#define m_RGA2_INT_LINE_WR_CLEAR (1 << 16)
#define m_RGA2_INT_LINE_RD_CLEAR (1 << 15)
#define m_RGA2_INT_LINE_WR_EN (1 << 14)
@@ -153,17 +161,23 @@
#define m_RGA2_INT_ERROR_FLAG_MASK \
( \
m_RGA2_INT_MMU_INT_FLAG | \
m_RGA2_INT_ERROR_INT_FLAG \
m_RGA2_INT_ERROR_INT_FLAG | \
m_RGA2_INT_SCL_ERROR_INTR | \
m_RGA2_INT_FBCIN_DEC_ERROR \
)
#define m_RGA2_INT_ERROR_CLEAR_MASK \
( \
m_RGA2_INT_MMU_INT_CLEAR | \
m_RGA2_INT_ERROR_INT_CLEAR \
m_RGA2_INT_MMU_INT_CLEAR | \
m_RGA2_INT_ERROR_INT_CLEAR | \
m_RGA2_INT_SCL_ERROR_CLEAR | \
m_RGA2_INT_FBCIN_DEC_ERROR_CLEAR \
)
#define m_RGA2_INT_ERROR_ENABLE_MASK \
( \
m_RGA2_INT_MMU_INT_EN | \
m_RGA2_INT_ERROR_INT_EN \
m_RGA2_INT_ERROR_INT_EN | \
m_RGA2_INT_SCL_ERROR_EN | \
m_RGA2_INT_FBCIN_DEC_ERROR_EN \
)
#define s_RGA2_INT_LINE_WR_CLEAR(x) ((x & 0x1) << 16)

View File

@@ -88,7 +88,7 @@
#define DRIVER_MAJOR_VERISON 1
#define DRIVER_MINOR_VERSION 3
#define DRIVER_REVISION_VERSION 7
#define DRIVER_REVISION_VERSION 8
#define DRIVER_PATCH_VERSION
#define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \

View File

@@ -133,6 +133,22 @@ static void rga2_scale_down_bilinear_protect(u32 *param_fix, u32 *src_fix,
*src_fix = final_steps + 1;
}
static void rag2_scale_down_average_protect(u32 *param_fix, u32 param,
u32 src, u32 dst)
{
/* division Loss */
param = param + 1;
/*
* Ensure that the (src - 1) drop point is to the left of the last
* point of the dst.
*/
while ((param * (src - 1)) > (dst << 16))
param--;
*param_fix = param;
}
static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg)
{
u32 *bRGA_SRC_X_FACTOR;
@@ -182,7 +198,8 @@ static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg)
((*bRGA_SRC_ACT_INFO & (~m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH)) |
s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH((src_fix - 1)));
} else {
param_x = ((dw << 16) + (sw / 2)) / sw;
param_x = (dw << 16) / sw;
rag2_scale_down_average_protect(&param_x, param_x, sw, dw);
*bRGA_SRC_X_FACTOR |= ((param_x & 0xffff) << 0);
}
@@ -219,7 +236,8 @@ static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg)
((*bRGA_SRC_ACT_INFO & (~m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT)) |
s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT((src_fix - 1)));
} else {
param_y = ((dh << 16) + (sh / 2)) / sh;
param_y = (dh << 16) / sh;
rag2_scale_down_average_protect(&param_y, param_y, sh, dh);
*bRGA_SRC_Y_FACTOR |= ((param_y & 0xffff) << 0);
}
@@ -3250,6 +3268,12 @@ static int rga2_isr_thread(struct rga_job *job, struct rga_scheduler_t *schedule
} else if (job->intr_status & m_RGA2_INT_MMU_INT_FLAG) {
rga_job_err(job, "mmu failed, please check size of the buffer or whether the buffer has been freed.\n");
job->ret = -EACCES;
} else if (job->intr_status & m_RGA2_INT_SCL_ERROR_INTR) {
rga_job_err(job, "scale failed, check scale config or formula.\n");
job->ret = -EACCES;
} else if (job->intr_status & m_RGA2_INT_FBCIN_DEC_ERROR) {
rga_job_err(job, "FBC decode failed, please check if the source data is FBC data.\n");
job->ret = -EACCES;
}
if (job->ret == 0) {

View File

@@ -1,51 +0,0 @@
/*
* include/linux/gpio_detection.h
*
* Platform data structure for GPIO detection driver
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __GPIO_DETECTION_H
#define __GPIO_DETECTION_H
#define GPIO_EVENT 1
/*
* gpio event
* @val: 0 event active, 1 event over
* @name: event name
*/
struct gpio_event {
int val;
const char *name;
};
#if IS_ENABLED(CONFIG_GPIO_DET)
int gpio_det_register_notifier(struct notifier_block *nb);
int gpio_det_unregister_notifier(struct notifier_block *nb);
int gpio_det_notifier_call_chain(unsigned long val, void *v);
#else
static inline int gpio_det_register_notifier(struct notifier_block *nb)
{
return -EINVAL;
};
static inline int gpio_det_unregister_notifier(struct notifier_block *nb)
{
return -EINVAL;
};
static inline int gpio_det_notifier_call_chain(unsigned long val, void *v)
{
return -EINVAL;
};
#endif
#endif

View File

@@ -8,6 +8,9 @@
#include <linux/types.h>
#define PHY_SUBMODE_DP 0
#define PHY_SUBMODE_EDP 1
/**
* struct phy_configure_opts_dp - DisplayPort PHY configuration set
*

View File

@@ -24,11 +24,7 @@ enum dvbm_cmd {
DVBM_ISP_CMD_BUTT,
DVBM_VEPU_CMD_BASE = 0x10,
DVBM_VEPU_SET_RESYNC,
DVBM_VEPU_SET_CFG,
DVBM_VEPU_GET_ADR,
DVBM_VEPU_GET_FRAME_INFO,
DVBM_VEPU_DUMP_REGS,
DVBM_VEPU_CMD_BUTT,
};
@@ -42,6 +38,9 @@ enum isp_frame_status {
enum dvbm_cb_event {
DVBM_ISP_EVENT_BASE = 0,
DVBM_ISP_REQ_CONNECT,
DVBM_ISP_REQ_DISCONNECT,
DVBM_ISP_SET_DVBM_CFG,
DVBM_ISP_EVENT_BUTT,
DVBM_VEPU_EVENT_BASE = 0x10,
@@ -60,9 +59,7 @@ struct dvbm_port {
};
struct dvbm_isp_cfg_t {
u32 fmt;
u32 timeout;
u32 chan_id;
struct dmabuf *buf;
dma_addr_t dma_addr;
u32 ybuf_top;
@@ -75,12 +72,6 @@ struct dvbm_isp_cfg_t {
u32 cbuf_fstd;
};
struct dvbm_isp_frm_cfg {
s32 frm_idx;
u32 ybuf_start;
u32 cbuf_start;
};
struct dvbm_isp_frm_info {
u32 frame_cnt;
u32 line_cnt;
@@ -96,14 +87,7 @@ struct dvbm_addr_cfg {
u32 cbuf_bot;
u32 cbuf_sadr;
u32 frame_id;
u32 line_cnt;
u32 overflow;
};
struct dvbm_vepu_cfg {
u32 auto_resyn;
u32 ignore_vepu_cnct_ack;
u32 start_point_after_vepu_cnct;
u32 chan_id;
};
typedef int (*dvbm_callback)(void *ctx, enum dvbm_cb_event event, void *arg);
@@ -119,8 +103,8 @@ struct dvbm_cb {
struct dvbm_port *rk_dvbm_get_port(struct platform_device *pdev,
enum dvbm_port_dir dir);
int rk_dvbm_put(struct dvbm_port *port);
int rk_dvbm_link(struct dvbm_port *port);
int rk_dvbm_unlink(struct dvbm_port *port);
int rk_dvbm_link(struct dvbm_port *port, int id);
int rk_dvbm_unlink(struct dvbm_port *port, int id);
int rk_dvbm_set_cb(struct dvbm_port *port, struct dvbm_cb *cb);
int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg);
@@ -137,11 +121,11 @@ static inline int rk_dvbm_put(struct dvbm_port *port)
return -ENODEV;
}
static inline int rk_dvbm_link(struct dvbm_port *port)
static inline int rk_dvbm_link(struct dvbm_port *port, int id)
{
return -ENODEV;
}
static inline int rk_dvbm_unlink(struct dvbm_port *port)
static inline int rk_dvbm_unlink(struct dvbm_port *port, int id)
{
return -ENODEV;
}