mirror of
https://github.com/torvalds/linux.git
synced 2026-05-21 13:27:57 +02:00
Samsung SoC drivers for v6.16
Several improvements to Exynos ACPM (Alive Clock and Power Manager)
driver:
1. Handle communication timeous better.
2. Avoid sleeping, so users (PMIC) can still transfer during system
shutdown.
3. Fix reading longer messages from them firmware.
4. Deferred probe improvements.
5. Model the user of ACPM - PMIC - a as child device and export
devm_acpm_get_by_node() for such use case.
-----BEGIN PGP SIGNATURE-----
iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmgTTgYQHGtyemtAa2Vy
bmVsLm9yZwAKCRDBN2bmhouD14JRD/99MfrKN3VfNDd7KLN5HSl+5Evw7oj1G/Dc
3CyJFjJyclEy8VxvWLOdv5d33zgf8LIZSF3zobU9EhtYLEbZ/N1iEtr+R2qhycRj
RfVw3r+lUnLF5D4gk5eTanZxvNxO6OxHc/oJfmoIZ7S0Tn6bFjwuK//6L6fZhVHj
j/0G4f71ec3Yx7bQgHpz+CbxBXwFkkNLX3zfWnbgUvM0hFJhxR68iQiSsraTP0P2
BSobaBfbRMz5yRO9MnQ/U6w/VY1NRndwX0BTxdkXTU39S1dhFIU83k4gVm4eaKPp
oPlCcbNMdvRVK7F0vA4x28cIeLI8yzU4p4/vZqq7JaFvsuydRTP043/x+zboUuQD
EFb09aC3IZLFHzXG4/AT+TfoPMB99HRlgVXBaw16RfbWQKo46khI3j4PniHqttAs
gfefNnzvOfyBpulB3gCLdaBuYOHZi90wCkTb9OJlzxV8k6z8pVfFnXsNPrK+L4Kn
x/JgdrBuLtxM6bLoV+eN0PYy+xrPW4y1nwdWX3NIoRCRSwYXnCt/jG9YUK7Wtqfi
GDrlE9gInWZO8X3n1EKDo+FUkeEb1QUCr+yQcHpTR5uLYIvjs8brxyIfy0omlwTx
xfGJazdRtnvxZm9YCH0MumEgHdlt6AYoifVz90+rW0sqHPGfLN/Nu3RHRMe49twA
mEBEVghlMg==
=Nd7d
-----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmgebk4ACgkQYKtH/8kJ
UidZ4Q/9Ff++EBBh1goLVPdaLyHO9XzaCZIszLh2YTBrp71YUyZ8EHnzuCrbj8v3
O0ChbqMCfDxNKsTNsLCHNIjUZ3D0qq6fyC83OnYtb92KJ7AlxCYVqF/4ib/XwCZ3
tX7rg76BKBSQnj3d5oH8mf5Eun93rv6325sWgXQytpPsYAx/BGhNtdHQNDXYW9Hs
cTiu41V3+EFx1o2RNWHGbRlVHKua5owFgeH3alfMNkAh+XFnuquzvjbHzyFoknRy
w50BOYUKgTNb0XRG5qOaZ3HwF32RRHXde7iIDkzTvuHdV9SQWw2cE4FRkuAqoswh
jxQaJi6XNr86nmsOrIdDlBT7Yztggxx51vJP1WMiIKHGximhLoooAhOyvxXuA6vG
AB4A2EPWLDSNgQcBh2qrImkFi4VGx+bqk7NrWMjN961Vy854P7bzUyJLEFWUo6DU
M5TWoOdPhS1Cn751aTJOdTUeDXmppZj1G9vr0oSBqUZaXIWPg5yvofoWA2iwbIcC
NaG5qd6aN9WOmIUYXjFUnvsJ9NJv3Pr/vQcPK1cmQbPR027E05m7NAoEafKC1ZQs
uyxRZVdwvIRwzFbHeGQ63DJB6afbNNowTPZDYTImUfpyomOJOZOu7peH2rsyCnBP
4NmoEMBB1tnFkntNb4//xWUnmcTN/+zHGBWBtTsi0MWv7Gzze4w=
=CqLR
-----END PGP SIGNATURE-----
Merge tag 'samsung-drivers-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into soc/drivers
Samsung SoC drivers for v6.16
Several improvements to Exynos ACPM (Alive Clock and Power Manager)
driver:
1. Handle communication timeous better.
2. Avoid sleeping, so users (PMIC) can still transfer during system
shutdown.
3. Fix reading longer messages from them firmware.
4. Deferred probe improvements.
5. Model the user of ACPM - PMIC - a as child device and export
devm_acpm_get_by_node() for such use case.
* tag 'samsung-drivers-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux:
firmware: exynos-acpm: Correct kerneldoc and use typical np argument name
firmware: exynos-acpm: introduce devm_acpm_get_by_node()
firmware: exynos-acpm: populate devices from device tree data
firmware: exynos-acpm: silence EPROBE_DEFER error on boot
firmware: exynos-acpm: fix reading longer results
dt-bindings: firmware: google,gs101-acpm-ipc: add PMIC child node
firmware: exynos-acpm: allow use during system shutdown
firmware: exynos-acpm: use ktime APIs for timeout detection
Link: https://lore.kernel.org/r/20250501103541.13795-2-krzysztof.kozlowski@linaro.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
7ebbb8416a
|
|
@ -27,6 +27,15 @@ properties:
|
|||
mboxes:
|
||||
maxItems: 1
|
||||
|
||||
pmic:
|
||||
description: Child node describing the main PMIC.
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: samsung,s2mpg10-pmic
|
||||
|
||||
shmem:
|
||||
description:
|
||||
List of phandle pointing to the shared memory (SHM) area. The memory
|
||||
|
|
@ -43,8 +52,34 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
power-management {
|
||||
compatible = "google,gs101-acpm-ipc";
|
||||
mboxes = <&ap2apm_mailbox>;
|
||||
shmem = <&apm_sram>;
|
||||
|
||||
pmic {
|
||||
compatible = "samsung,s2mpg10-pmic";
|
||||
interrupts-extended = <&gpa0 6 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
regulators {
|
||||
LDO1 {
|
||||
regulator-name = "vdd_ldo1";
|
||||
regulator-min-microvolt = <700000>;
|
||||
regulator-max-microvolt = <1300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
BUCK1 {
|
||||
regulator-name = "vdd_mif";
|
||||
regulator-min-microvolt = <450000>;
|
||||
regulator-max-microvolt = <1300000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,13 +43,13 @@ static inline u32 acpm_pmic_get_bulk(u32 data, unsigned int i)
|
|||
return (data >> (ACPM_PMIC_BULK_SHIFT * i)) & ACPM_PMIC_BULK_MASK;
|
||||
}
|
||||
|
||||
static void acpm_pmic_set_xfer(struct acpm_xfer *xfer, u32 *cmd,
|
||||
static void acpm_pmic_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
|
||||
unsigned int acpm_chan_id)
|
||||
{
|
||||
xfer->txd = cmd;
|
||||
xfer->rxd = cmd;
|
||||
xfer->txlen = sizeof(cmd);
|
||||
xfer->rxlen = sizeof(cmd);
|
||||
xfer->txlen = cmdlen;
|
||||
xfer->rxlen = cmdlen;
|
||||
xfer->acpm_chan_id = acpm_chan_id;
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ int acpm_pmic_read_reg(const struct acpm_handle *handle,
|
|||
int ret;
|
||||
|
||||
acpm_pmic_init_read_cmd(cmd, type, reg, chan);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
|
||||
|
||||
ret = acpm_do_xfer(handle, &xfer);
|
||||
if (ret)
|
||||
|
|
@ -104,7 +104,7 @@ int acpm_pmic_bulk_read(const struct acpm_handle *handle,
|
|||
return -EINVAL;
|
||||
|
||||
acpm_pmic_init_bulk_read_cmd(cmd, type, reg, chan, count);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
|
||||
|
||||
ret = acpm_do_xfer(handle, &xfer);
|
||||
if (ret)
|
||||
|
|
@ -144,7 +144,7 @@ int acpm_pmic_write_reg(const struct acpm_handle *handle,
|
|||
int ret;
|
||||
|
||||
acpm_pmic_init_write_cmd(cmd, type, reg, chan, value);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
|
||||
|
||||
ret = acpm_do_xfer(handle, &xfer);
|
||||
if (ret)
|
||||
|
|
@ -184,7 +184,7 @@ int acpm_pmic_bulk_write(const struct acpm_handle *handle,
|
|||
return -EINVAL;
|
||||
|
||||
acpm_pmic_init_bulk_write_cmd(cmd, type, reg, chan, count, buf);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
|
||||
|
||||
ret = acpm_do_xfer(handle, &xfer);
|
||||
if (ret)
|
||||
|
|
@ -214,7 +214,7 @@ int acpm_pmic_update_reg(const struct acpm_handle *handle,
|
|||
int ret;
|
||||
|
||||
acpm_pmic_init_update_cmd(cmd, type, reg, chan, value, mask);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id);
|
||||
acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
|
||||
|
||||
ret = acpm_do_xfer(handle, &xfer);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/mailbox/exynos-message.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -32,8 +33,7 @@
|
|||
|
||||
#define ACPM_PROTOCOL_SEQNUM GENMASK(21, 16)
|
||||
|
||||
/* The unit of counter is 20 us. 5000 * 20 = 100 ms */
|
||||
#define ACPM_POLL_TIMEOUT 5000
|
||||
#define ACPM_POLL_TIMEOUT_US (100 * USEC_PER_MSEC)
|
||||
#define ACPM_TX_TIMEOUT_US 500000
|
||||
|
||||
#define ACPM_GS101_INITDATA_BASE 0xa000
|
||||
|
|
@ -284,12 +284,13 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
|
|||
const struct acpm_xfer *xfer)
|
||||
{
|
||||
struct device *dev = achan->acpm->dev;
|
||||
unsigned int cnt_20us = 0;
|
||||
ktime_t timeout;
|
||||
u32 seqnum;
|
||||
int ret;
|
||||
|
||||
seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]);
|
||||
|
||||
timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US);
|
||||
do {
|
||||
ret = acpm_get_rx(achan, xfer);
|
||||
if (ret)
|
||||
|
|
@ -299,12 +300,11 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
|
|||
return 0;
|
||||
|
||||
/* Determined experimentally. */
|
||||
usleep_range(20, 30);
|
||||
cnt_20us++;
|
||||
} while (cnt_20us < ACPM_POLL_TIMEOUT);
|
||||
udelay(20);
|
||||
} while (ktime_before(ktime_get(), timeout));
|
||||
|
||||
dev_err(dev, "Timeout! ch:%u s:%u bitmap:%lx, cnt_20us = %d.\n",
|
||||
achan->id, seqnum, achan->bitmap_seqnum[0], cnt_20us);
|
||||
dev_err(dev, "Timeout! ch:%u s:%u bitmap:%lx.\n",
|
||||
achan->id, seqnum, achan->bitmap_seqnum[0]);
|
||||
|
||||
return -ETIME;
|
||||
}
|
||||
|
|
@ -633,7 +633,7 @@ static int acpm_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, acpm);
|
||||
|
||||
return 0;
|
||||
return devm_of_platform_populate(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -661,43 +661,30 @@ static void devm_acpm_release(struct device *dev, void *res)
|
|||
}
|
||||
|
||||
/**
|
||||
* acpm_get_by_phandle() - get the ACPM handle using DT phandle.
|
||||
* @dev: device pointer requesting ACPM handle.
|
||||
* @property: property name containing phandle on ACPM node.
|
||||
* acpm_get_by_node() - get the ACPM handle using node pointer.
|
||||
* @dev: device pointer requesting ACPM handle.
|
||||
* @np: ACPM device tree node.
|
||||
*
|
||||
* Return: pointer to handle on success, ERR_PTR(-errno) otherwise.
|
||||
*/
|
||||
static const struct acpm_handle *acpm_get_by_phandle(struct device *dev,
|
||||
const char *property)
|
||||
static const struct acpm_handle *acpm_get_by_node(struct device *dev,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct device_node *acpm_np;
|
||||
struct device_link *link;
|
||||
struct acpm_info *acpm;
|
||||
|
||||
acpm_np = of_parse_phandle(dev->of_node, property, 0);
|
||||
if (!acpm_np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
pdev = of_find_device_by_node(acpm_np);
|
||||
if (!pdev) {
|
||||
dev_err(dev, "Cannot find device node %s\n", acpm_np->name);
|
||||
of_node_put(acpm_np);
|
||||
pdev = of_find_device_by_node(np);
|
||||
if (!pdev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
of_node_put(acpm_np);
|
||||
|
||||
acpm = platform_get_drvdata(pdev);
|
||||
if (!acpm) {
|
||||
dev_err(dev, "Cannot get drvdata from %s\n",
|
||||
dev_name(&pdev->dev));
|
||||
platform_device_put(pdev);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
if (!try_module_get(pdev->dev.driver->owner)) {
|
||||
dev_err(dev, "Cannot get module reference.\n");
|
||||
platform_device_put(pdev);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
|
@ -716,14 +703,14 @@ static const struct acpm_handle *acpm_get_by_phandle(struct device *dev,
|
|||
}
|
||||
|
||||
/**
|
||||
* devm_acpm_get_by_phandle() - managed get handle using phandle.
|
||||
* @dev: device pointer requesting ACPM handle.
|
||||
* @property: property name containing phandle on ACPM node.
|
||||
* devm_acpm_get_by_node() - managed get handle using node pointer.
|
||||
* @dev: device pointer requesting ACPM handle.
|
||||
* @np: ACPM device tree node.
|
||||
*
|
||||
* Return: pointer to handle on success, ERR_PTR(-errno) otherwise.
|
||||
*/
|
||||
const struct acpm_handle *devm_acpm_get_by_phandle(struct device *dev,
|
||||
const char *property)
|
||||
const struct acpm_handle *devm_acpm_get_by_node(struct device *dev,
|
||||
struct device_node *np)
|
||||
{
|
||||
const struct acpm_handle **ptr, *handle;
|
||||
|
||||
|
|
@ -731,7 +718,7 @@ const struct acpm_handle *devm_acpm_get_by_phandle(struct device *dev,
|
|||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
handle = acpm_get_by_phandle(dev, property);
|
||||
handle = acpm_get_by_node(dev, np);
|
||||
if (!IS_ERR(handle)) {
|
||||
*ptr = handle;
|
||||
devres_add(dev, ptr);
|
||||
|
|
@ -741,6 +728,7 @@ const struct acpm_handle *devm_acpm_get_by_phandle(struct device *dev,
|
|||
|
||||
return handle;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_acpm_get_by_node);
|
||||
|
||||
static const struct acpm_match_data acpm_gs101 = {
|
||||
.initdata_base = ACPM_GS101_INITDATA_BASE,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
struct acpm_handle;
|
||||
struct device_node;
|
||||
|
||||
struct acpm_pmic_ops {
|
||||
int (*read_reg)(const struct acpm_handle *handle,
|
||||
|
|
@ -44,6 +45,7 @@ struct acpm_handle {
|
|||
|
||||
struct device;
|
||||
|
||||
const struct acpm_handle *devm_acpm_get_by_phandle(struct device *dev,
|
||||
const char *property);
|
||||
const struct acpm_handle *devm_acpm_get_by_node(struct device *dev,
|
||||
struct device_node *np);
|
||||
|
||||
#endif /* __EXYNOS_ACPM_PROTOCOL_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user