Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
9b4a1915
Commit
9b4a1915
authored
Feb 04, 2023
by
Bjorn Andersson
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '20230201041853.1934355-1-quic_bjorande@quicinc.com' into drivers-for-6.3
parents
c5d52d7b
080b4e24
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
958 additions
and
0 deletions
+958
-0
Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
...ntation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
+95
-0
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Kconfig
+15
-0
drivers/soc/qcom/Makefile
drivers/soc/qcom/Makefile
+2
-0
drivers/soc/qcom/pmic_glink.c
drivers/soc/qcom/pmic_glink.c
+336
-0
drivers/soc/qcom/pmic_glink_altmode.c
drivers/soc/qcom/pmic_glink_altmode.c
+478
-0
include/linux/soc/qcom/pmic_glink.h
include/linux/soc/qcom/pmic_glink.h
+32
-0
No files found.
Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
0 → 100644
View file @
9b4a1915
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/soc/qcom/qcom,pmic-glink.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Qualcomm PMIC GLINK firmware interface for battery management, USB
Type-C and other things.
maintainers
:
-
Bjorn Andersson <andersson@kernel.org>
description
:
The PMIC GLINK service, running on a coprocessor on some modern Qualcomm
platforms and implement USB Type-C handling and battery management. This
binding describes the component in the OS used to communicate with the
firmware and connect it's resources to those described in the Devicetree,
particularly the USB Type-C controllers relationship with USB and DisplayPort
components.
properties
:
compatible
:
items
:
-
enum
:
-
qcom,sc8180x-pmic-glink
-
qcom,sc8280xp-pmic-glink
-
qcom,sm8350-pmic-glink
-
const
:
qcom,pmic-glink
'
#address-cells'
:
const
:
1
'
#size-cells'
:
const
:
0
patternProperties
:
'
^connector@\d$'
:
$ref
:
/schemas/connector/usb-connector.yaml#
properties
:
reg
:
true
required
:
-
reg
unevaluatedProperties
:
false
required
:
-
compatible
additionalProperties
:
false
examples
:
-
|+
pmic-glink {
compatible = "qcom,sc8280xp-pmic-glink", "qcom,pmic-glink";
#address-cells = <1>;
#size-cells = <0>;
connector@0 {
compatible = "usb-c-connector";
reg = <0>;
power-role = "dual";
data-role = "dual";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
endpoint {
remote-endpoint = <&usb_role>;
};
};
port@1 {
reg = <1>;
endpoint {
remote-endpoint = <&ss_phy_out>;
};
};
port@2 {
reg = <2>;
endpoint {
remote-endpoint = <&sbu_mux>;
};
};
};
};
};
...
drivers/soc/qcom/Kconfig
View file @
9b4a1915
...
...
@@ -92,6 +92,21 @@ config QCOM_PDR_HELPERS
tristate
select QCOM_QMI_HELPERS
config QCOM_PMIC_GLINK
tristate "Qualcomm PMIC GLINK driver"
depends on RPMSG
depends on TYPEC
depends on DRM
select AUXILIARY_BUS
select QCOM_PDR_HELPERS
help
The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
USB and battery firmware running on one of the coprocessors in
several modern Qualcomm platforms.
Say yes here to support USB-C and battery status on modern Qualcomm
platforms.
config QCOM_QMI_HELPERS
tristate
depends on NET
...
...
drivers/soc/qcom/Makefile
View file @
9b4a1915
...
...
@@ -8,6 +8,8 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER)
+=
mdt_loader.o
obj-$(CONFIG_QCOM_OCMEM)
+=
ocmem.o
obj-$(CONFIG_QCOM_PDR_HELPERS)
+=
pdr_interface.o
obj-$(CONFIG_QCOM_PMIC_GLINK)
+=
pmic_glink.o
obj-$(CONFIG_QCOM_PMIC_GLINK)
+=
pmic_glink_altmode.o
obj-$(CONFIG_QCOM_QMI_HELPERS)
+=
qmi_helpers.o
qmi_helpers-y
+=
qmi_encdec.o qmi_interface.o
obj-$(CONFIG_QCOM_RAMP_CTRL)
+=
ramp_controller.o
...
...
drivers/soc/qcom/pmic_glink.c
0 → 100644
View file @
9b4a1915
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Linaro Ltd
*/
#include <linux/auxiliary_bus.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rpmsg.h>
#include <linux/slab.h>
#include <linux/soc/qcom/pdr.h>
#include <linux/soc/qcom/pmic_glink.h>
struct
pmic_glink
{
struct
device
*
dev
;
struct
pdr_handle
*
pdr
;
struct
rpmsg_endpoint
*
ept
;
struct
auxiliary_device
altmode_aux
;
struct
auxiliary_device
ps_aux
;
struct
auxiliary_device
ucsi_aux
;
/* serializing client_state and pdr_state updates */
struct
mutex
state_lock
;
unsigned
int
client_state
;
unsigned
int
pdr_state
;
/* serializing clients list updates */
struct
mutex
client_lock
;
struct
list_head
clients
;
};
static
struct
pmic_glink
*
__pmic_glink
;
static
DEFINE_MUTEX
(
__pmic_glink_lock
);
struct
pmic_glink_client
{
struct
list_head
node
;
struct
pmic_glink
*
pg
;
unsigned
int
id
;
void
(
*
cb
)(
const
void
*
data
,
size_t
len
,
void
*
priv
);
void
(
*
pdr_notify
)(
void
*
priv
,
int
state
);
void
*
priv
;
};
static
void
_devm_pmic_glink_release_client
(
struct
device
*
dev
,
void
*
res
)
{
struct
pmic_glink_client
*
client
=
(
struct
pmic_glink_client
*
)
res
;
struct
pmic_glink
*
pg
=
client
->
pg
;
mutex_lock
(
&
pg
->
client_lock
);
list_del
(
&
client
->
node
);
mutex_unlock
(
&
pg
->
client_lock
);
}
struct
pmic_glink_client
*
devm_pmic_glink_register_client
(
struct
device
*
dev
,
unsigned
int
id
,
void
(
*
cb
)(
const
void
*
,
size_t
,
void
*
),
void
(
*
pdr
)(
void
*
,
int
),
void
*
priv
)
{
struct
pmic_glink_client
*
client
;
struct
pmic_glink
*
pg
=
dev_get_drvdata
(
dev
->
parent
);
client
=
devres_alloc
(
_devm_pmic_glink_release_client
,
sizeof
(
*
client
),
GFP_KERNEL
);
if
(
!
client
)
return
ERR_PTR
(
-
ENOMEM
);
client
->
pg
=
pg
;
client
->
id
=
id
;
client
->
cb
=
cb
;
client
->
pdr_notify
=
pdr
;
client
->
priv
=
priv
;
mutex_lock
(
&
pg
->
client_lock
);
list_add
(
&
client
->
node
,
&
pg
->
clients
);
mutex_unlock
(
&
pg
->
client_lock
);
devres_add
(
dev
,
client
);
return
client
;
}
EXPORT_SYMBOL_GPL
(
devm_pmic_glink_register_client
);
int
pmic_glink_send
(
struct
pmic_glink_client
*
client
,
void
*
data
,
size_t
len
)
{
struct
pmic_glink
*
pg
=
client
->
pg
;
return
rpmsg_send
(
pg
->
ept
,
data
,
len
);
}
EXPORT_SYMBOL_GPL
(
pmic_glink_send
);
static
int
pmic_glink_rpmsg_callback
(
struct
rpmsg_device
*
rpdev
,
void
*
data
,
int
len
,
void
*
priv
,
u32
addr
)
{
struct
pmic_glink_client
*
client
;
struct
pmic_glink_hdr
*
hdr
;
struct
pmic_glink
*
pg
=
dev_get_drvdata
(
&
rpdev
->
dev
);
if
(
len
<
sizeof
(
*
hdr
))
{
dev_warn
(
pg
->
dev
,
"ignoring truncated message
\n
"
);
return
0
;
}
hdr
=
data
;
list_for_each_entry
(
client
,
&
pg
->
clients
,
node
)
{
if
(
client
->
id
==
le32_to_cpu
(
hdr
->
owner
))
client
->
cb
(
data
,
len
,
client
->
priv
);
}
return
0
;
}
static
void
pmic_glink_aux_release
(
struct
device
*
dev
)
{}
static
int
pmic_glink_add_aux_device
(
struct
pmic_glink
*
pg
,
struct
auxiliary_device
*
aux
,
const
char
*
name
)
{
struct
device
*
parent
=
pg
->
dev
;
int
ret
;
aux
->
name
=
name
;
aux
->
dev
.
parent
=
parent
;
aux
->
dev
.
release
=
pmic_glink_aux_release
;
device_set_of_node_from_dev
(
&
aux
->
dev
,
parent
);
ret
=
auxiliary_device_init
(
aux
);
if
(
ret
)
return
ret
;
ret
=
auxiliary_device_add
(
aux
);
if
(
ret
)
auxiliary_device_uninit
(
aux
);
return
ret
;
}
static
void
pmic_glink_del_aux_device
(
struct
pmic_glink
*
pg
,
struct
auxiliary_device
*
aux
)
{
auxiliary_device_delete
(
aux
);
auxiliary_device_uninit
(
aux
);
}
static
void
pmic_glink_state_notify_clients
(
struct
pmic_glink
*
pg
)
{
struct
pmic_glink_client
*
client
;
unsigned
int
new_state
=
pg
->
client_state
;
if
(
pg
->
client_state
!=
SERVREG_SERVICE_STATE_UP
)
{
if
(
pg
->
pdr_state
==
SERVREG_SERVICE_STATE_UP
&&
pg
->
ept
)
new_state
=
SERVREG_SERVICE_STATE_UP
;
}
else
{
if
(
pg
->
pdr_state
==
SERVREG_SERVICE_STATE_UP
&&
pg
->
ept
)
new_state
=
SERVREG_SERVICE_STATE_DOWN
;
}
if
(
new_state
!=
pg
->
client_state
)
{
list_for_each_entry
(
client
,
&
pg
->
clients
,
node
)
client
->
pdr_notify
(
client
->
priv
,
new_state
);
pg
->
client_state
=
new_state
;
}
}
static
void
pmic_glink_pdr_callback
(
int
state
,
char
*
svc_path
,
void
*
priv
)
{
struct
pmic_glink
*
pg
=
priv
;
mutex_lock
(
&
pg
->
state_lock
);
pg
->
pdr_state
=
state
;
pmic_glink_state_notify_clients
(
pg
);
mutex_unlock
(
&
pg
->
state_lock
);
}
static
int
pmic_glink_rpmsg_probe
(
struct
rpmsg_device
*
rpdev
)
{
struct
pmic_glink
*
pg
=
__pmic_glink
;
int
ret
=
0
;
mutex_lock
(
&
__pmic_glink_lock
);
if
(
!
pg
)
{
ret
=
dev_err_probe
(
&
rpdev
->
dev
,
-
ENODEV
,
"no pmic_glink device to attach to
\n
"
);
goto
out_unlock
;
}
dev_set_drvdata
(
&
rpdev
->
dev
,
pg
);
mutex_lock
(
&
pg
->
state_lock
);
pg
->
ept
=
rpdev
->
ept
;
pmic_glink_state_notify_clients
(
pg
);
mutex_unlock
(
&
pg
->
state_lock
);
out_unlock:
mutex_unlock
(
&
__pmic_glink_lock
);
return
ret
;
}
static
void
pmic_glink_rpmsg_remove
(
struct
rpmsg_device
*
rpdev
)
{
struct
pmic_glink
*
pg
;
mutex_lock
(
&
__pmic_glink_lock
);
pg
=
__pmic_glink
;
if
(
!
pg
)
goto
out_unlock
;
mutex_lock
(
&
pg
->
state_lock
);
pg
->
ept
=
NULL
;
pmic_glink_state_notify_clients
(
pg
);
mutex_unlock
(
&
pg
->
state_lock
);
out_unlock:
mutex_unlock
(
&
__pmic_glink_lock
);
}
static
const
struct
rpmsg_device_id
pmic_glink_rpmsg_id_match
[]
=
{
{
"PMIC_RTR_ADSP_APPS"
},
{}
};
static
struct
rpmsg_driver
pmic_glink_rpmsg_driver
=
{
.
probe
=
pmic_glink_rpmsg_probe
,
.
remove
=
pmic_glink_rpmsg_remove
,
.
callback
=
pmic_glink_rpmsg_callback
,
.
id_table
=
pmic_glink_rpmsg_id_match
,
.
drv
=
{
.
name
=
"qcom_pmic_glink_rpmsg"
,
},
};
static
int
pmic_glink_probe
(
struct
platform_device
*
pdev
)
{
struct
pdr_service
*
service
;
struct
pmic_glink
*
pg
;
int
ret
;
pg
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pg
),
GFP_KERNEL
);
if
(
!
pg
)
return
-
ENOMEM
;
dev_set_drvdata
(
&
pdev
->
dev
,
pg
);
pg
->
dev
=
&
pdev
->
dev
;
INIT_LIST_HEAD
(
&
pg
->
clients
);
mutex_init
(
&
pg
->
client_lock
);
mutex_init
(
&
pg
->
state_lock
);
ret
=
pmic_glink_add_aux_device
(
pg
,
&
pg
->
altmode_aux
,
"altmode"
);
if
(
ret
)
return
ret
;
ret
=
pmic_glink_add_aux_device
(
pg
,
&
pg
->
ps_aux
,
"power-supply"
);
if
(
ret
)
goto
out_release_altmode_aux
;
pg
->
pdr
=
pdr_handle_alloc
(
pmic_glink_pdr_callback
,
pg
);
if
(
IS_ERR
(
pg
->
pdr
))
{
ret
=
dev_err_probe
(
&
pdev
->
dev
,
PTR_ERR
(
pg
->
pdr
),
"failed to initialize pdr
\n
"
);
goto
out_release_aux_devices
;
}
service
=
pdr_add_lookup
(
pg
->
pdr
,
"tms/servreg"
,
"msm/adsp/charger_pd"
);
if
(
IS_ERR
(
service
))
{
ret
=
dev_err_probe
(
&
pdev
->
dev
,
PTR_ERR
(
service
),
"failed adding pdr lookup for charger_pd
\n
"
);
goto
out_release_pdr_handle
;
}
mutex_lock
(
&
__pmic_glink_lock
);
__pmic_glink
=
pg
;
mutex_unlock
(
&
__pmic_glink_lock
);
return
0
;
out_release_pdr_handle:
pdr_handle_release
(
pg
->
pdr
);
out_release_aux_devices:
pmic_glink_del_aux_device
(
pg
,
&
pg
->
ps_aux
);
out_release_altmode_aux:
pmic_glink_del_aux_device
(
pg
,
&
pg
->
altmode_aux
);
return
ret
;
}
static
int
pmic_glink_remove
(
struct
platform_device
*
pdev
)
{
struct
pmic_glink
*
pg
=
dev_get_drvdata
(
&
pdev
->
dev
);
pdr_handle_release
(
pg
->
pdr
);
pmic_glink_del_aux_device
(
pg
,
&
pg
->
ps_aux
);
pmic_glink_del_aux_device
(
pg
,
&
pg
->
altmode_aux
);
mutex_lock
(
&
__pmic_glink_lock
);
__pmic_glink
=
NULL
;
mutex_unlock
(
&
__pmic_glink_lock
);
return
0
;
}
static
const
struct
of_device_id
pmic_glink_of_match
[]
=
{
{
.
compatible
=
"qcom,pmic-glink"
,
},
{}
};
MODULE_DEVICE_TABLE
(
of
,
pmic_glink_of_match
);
static
struct
platform_driver
pmic_glink_driver
=
{
.
probe
=
pmic_glink_probe
,
.
remove
=
pmic_glink_remove
,
.
driver
=
{
.
name
=
"qcom_pmic_glink"
,
.
of_match_table
=
pmic_glink_of_match
,
},
};
static
int
pmic_glink_init
(
void
)
{
platform_driver_register
(
&
pmic_glink_driver
);
register_rpmsg_driver
(
&
pmic_glink_rpmsg_driver
);
return
0
;
};
module_init
(
pmic_glink_init
);
static
void
pmic_glink_exit
(
void
)
{
unregister_rpmsg_driver
(
&
pmic_glink_rpmsg_driver
);
platform_driver_unregister
(
&
pmic_glink_driver
);
};
module_exit
(
pmic_glink_exit
);
MODULE_DESCRIPTION
(
"Qualcomm PMIC GLINK driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/soc/qcom/pmic_glink_altmode.c
0 → 100644
View file @
9b4a1915
This diff is collapsed.
Click to expand it.
include/linux/soc/qcom/pmic_glink.h
0 → 100644
View file @
9b4a1915
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022, Linaro Ltd
*/
#ifndef __SOC_QCOM_PMIC_GLINK_H__
#define __SOC_QCOM_PMIC_GLINK_H__
struct
pmic_glink
;
struct
pmic_glink_client
;
#define PMIC_GLINK_OWNER_BATTMGR 32778
#define PMIC_GLINK_OWNER_USBC 32779
#define PMIC_GLINK_OWNER_USBC_PAN 32780
#define PMIC_GLINK_REQ_RESP 1
#define PMIC_GLINK_NOTIFY 2
struct
pmic_glink_hdr
{
__le32
owner
;
__le32
type
;
__le32
opcode
;
};
int
pmic_glink_send
(
struct
pmic_glink_client
*
client
,
void
*
data
,
size_t
len
);
struct
pmic_glink_client
*
devm_pmic_glink_register_client
(
struct
device
*
dev
,
unsigned
int
id
,
void
(
*
cb
)(
const
void
*
,
size_t
,
void
*
),
void
(
*
pdr
)(
void
*
,
int
),
void
*
priv
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment