mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
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:
@@ -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;
|
||||
};
|
||||
};
|
||||
@@ -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";
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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) &&
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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>");
|
||||
@@ -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>");
|
||||
@@ -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>");
|
||||
@@ -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
|
||||
|
||||
@@ -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 = ®->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 *)®->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 *)®->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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
/*
|
||||
* 1’b0 : the current ISP frame
|
||||
* 1’b1 : 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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(¶m_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(¶m_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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user