Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'samsung-drivers-6.16' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/krzk/linux into ib-firmware-mfd-6.16

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.

+70 -45
+35
Documentation/devicetree/bindings/firmware/google,gs101-acpm-ipc.yaml
··· 27 27 mboxes: 28 28 maxItems: 1 29 29 30 + pmic: 31 + description: Child node describing the main PMIC. 32 + type: object 33 + additionalProperties: true 34 + 35 + properties: 36 + compatible: 37 + const: samsung,s2mpg10-pmic 38 + 30 39 shmem: 31 40 description: 32 41 List of phandle pointing to the shared memory (SHM) area. The memory ··· 52 43 53 44 examples: 54 45 - | 46 + #include <dt-bindings/interrupt-controller/irq.h> 47 + 55 48 power-management { 56 49 compatible = "google,gs101-acpm-ipc"; 57 50 mboxes = <&ap2apm_mailbox>; 58 51 shmem = <&apm_sram>; 52 + 53 + pmic { 54 + compatible = "samsung,s2mpg10-pmic"; 55 + interrupts-extended = <&gpa0 6 IRQ_TYPE_LEVEL_LOW>; 56 + 57 + regulators { 58 + LDO1 { 59 + regulator-name = "vdd_ldo1"; 60 + regulator-min-microvolt = <700000>; 61 + regulator-max-microvolt = <1300000>; 62 + regulator-always-on; 63 + }; 64 + 65 + // ... 66 + 67 + BUCK1 { 68 + regulator-name = "vdd_mif"; 69 + regulator-min-microvolt = <450000>; 70 + regulator-max-microvolt = <1300000>; 71 + regulator-always-on; 72 + regulator-boot-on; 73 + }; 74 + }; 75 + }; 59 76 };
+8 -8
drivers/firmware/samsung/exynos-acpm-pmic.c
··· 43 43 return (data >> (ACPM_PMIC_BULK_SHIFT * i)) & ACPM_PMIC_BULK_MASK; 44 44 } 45 45 46 - static void acpm_pmic_set_xfer(struct acpm_xfer *xfer, u32 *cmd, 46 + static void acpm_pmic_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen, 47 47 unsigned int acpm_chan_id) 48 48 { 49 49 xfer->txd = cmd; 50 50 xfer->rxd = cmd; 51 - xfer->txlen = sizeof(cmd); 52 - xfer->rxlen = sizeof(cmd); 51 + xfer->txlen = cmdlen; 52 + xfer->rxlen = cmdlen; 53 53 xfer->acpm_chan_id = acpm_chan_id; 54 54 } 55 55 ··· 71 71 int ret; 72 72 73 73 acpm_pmic_init_read_cmd(cmd, type, reg, chan); 74 - acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id); 74 + acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id); 75 75 76 76 ret = acpm_do_xfer(handle, &xfer); 77 77 if (ret) ··· 104 104 return -EINVAL; 105 105 106 106 acpm_pmic_init_bulk_read_cmd(cmd, type, reg, chan, count); 107 - acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id); 107 + acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id); 108 108 109 109 ret = acpm_do_xfer(handle, &xfer); 110 110 if (ret) ··· 144 144 int ret; 145 145 146 146 acpm_pmic_init_write_cmd(cmd, type, reg, chan, value); 147 - acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id); 147 + acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id); 148 148 149 149 ret = acpm_do_xfer(handle, &xfer); 150 150 if (ret) ··· 184 184 return -EINVAL; 185 185 186 186 acpm_pmic_init_bulk_write_cmd(cmd, type, reg, chan, count, buf); 187 - acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id); 187 + acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id); 188 188 189 189 ret = acpm_do_xfer(handle, &xfer); 190 190 if (ret) ··· 214 214 int ret; 215 215 216 216 acpm_pmic_init_update_cmd(cmd, type, reg, chan, value, mask); 217 - acpm_pmic_set_xfer(&xfer, cmd, acpm_chan_id); 217 + acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id); 218 218 219 219 ret = acpm_do_xfer(handle, &xfer); 220 220 if (ret)
+23 -35
drivers/firmware/samsung/exynos-acpm.c
··· 15 15 #include <linux/firmware/samsung/exynos-acpm-protocol.h> 16 16 #include <linux/io.h> 17 17 #include <linux/iopoll.h> 18 + #include <linux/ktime.h> 18 19 #include <linux/mailbox/exynos-message.h> 19 20 #include <linux/mailbox_client.h> 20 21 #include <linux/module.h> ··· 33 32 34 33 #define ACPM_PROTOCOL_SEQNUM GENMASK(21, 16) 35 34 36 - /* The unit of counter is 20 us. 5000 * 20 = 100 ms */ 37 - #define ACPM_POLL_TIMEOUT 5000 35 + #define ACPM_POLL_TIMEOUT_US (100 * USEC_PER_MSEC) 38 36 #define ACPM_TX_TIMEOUT_US 500000 39 37 40 38 #define ACPM_GS101_INITDATA_BASE 0xa000 ··· 284 284 const struct acpm_xfer *xfer) 285 285 { 286 286 struct device *dev = achan->acpm->dev; 287 - unsigned int cnt_20us = 0; 287 + ktime_t timeout; 288 288 u32 seqnum; 289 289 int ret; 290 290 291 291 seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]); 292 292 293 + timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US); 293 294 do { 294 295 ret = acpm_get_rx(achan, xfer); 295 296 if (ret) ··· 300 299 return 0; 301 300 302 301 /* Determined experimentally. */ 303 - usleep_range(20, 30); 304 - cnt_20us++; 305 - } while (cnt_20us < ACPM_POLL_TIMEOUT); 302 + udelay(20); 303 + } while (ktime_before(ktime_get(), timeout)); 306 304 307 - dev_err(dev, "Timeout! ch:%u s:%u bitmap:%lx, cnt_20us = %d.\n", 308 - achan->id, seqnum, achan->bitmap_seqnum[0], cnt_20us); 305 + dev_err(dev, "Timeout! ch:%u s:%u bitmap:%lx.\n", 306 + achan->id, seqnum, achan->bitmap_seqnum[0]); 309 307 310 308 return -ETIME; 311 309 } ··· 633 633 634 634 platform_set_drvdata(pdev, acpm); 635 635 636 - return 0; 636 + return devm_of_platform_populate(dev); 637 637 } 638 638 639 639 /** ··· 661 661 } 662 662 663 663 /** 664 - * acpm_get_by_phandle() - get the ACPM handle using DT phandle. 665 - * @dev: device pointer requesting ACPM handle. 666 - * @property: property name containing phandle on ACPM node. 664 + * acpm_get_by_node() - get the ACPM handle using node pointer. 665 + * @dev: device pointer requesting ACPM handle. 666 + * @np: ACPM device tree node. 667 667 * 668 668 * Return: pointer to handle on success, ERR_PTR(-errno) otherwise. 669 669 */ 670 - static const struct acpm_handle *acpm_get_by_phandle(struct device *dev, 671 - const char *property) 670 + static const struct acpm_handle *acpm_get_by_node(struct device *dev, 671 + struct device_node *np) 672 672 { 673 673 struct platform_device *pdev; 674 - struct device_node *acpm_np; 675 674 struct device_link *link; 676 675 struct acpm_info *acpm; 677 676 678 - acpm_np = of_parse_phandle(dev->of_node, property, 0); 679 - if (!acpm_np) 680 - return ERR_PTR(-ENODEV); 681 - 682 - pdev = of_find_device_by_node(acpm_np); 683 - if (!pdev) { 684 - dev_err(dev, "Cannot find device node %s\n", acpm_np->name); 685 - of_node_put(acpm_np); 677 + pdev = of_find_device_by_node(np); 678 + if (!pdev) 686 679 return ERR_PTR(-EPROBE_DEFER); 687 - } 688 - 689 - of_node_put(acpm_np); 690 680 691 681 acpm = platform_get_drvdata(pdev); 692 682 if (!acpm) { 693 - dev_err(dev, "Cannot get drvdata from %s\n", 694 - dev_name(&pdev->dev)); 695 683 platform_device_put(pdev); 696 684 return ERR_PTR(-EPROBE_DEFER); 697 685 } 698 686 699 687 if (!try_module_get(pdev->dev.driver->owner)) { 700 - dev_err(dev, "Cannot get module reference.\n"); 701 688 platform_device_put(pdev); 702 689 return ERR_PTR(-EPROBE_DEFER); 703 690 } ··· 703 716 } 704 717 705 718 /** 706 - * devm_acpm_get_by_phandle() - managed get handle using phandle. 707 - * @dev: device pointer requesting ACPM handle. 708 - * @property: property name containing phandle on ACPM node. 719 + * devm_acpm_get_by_node() - managed get handle using node pointer. 720 + * @dev: device pointer requesting ACPM handle. 721 + * @np: ACPM device tree node. 709 722 * 710 723 * Return: pointer to handle on success, ERR_PTR(-errno) otherwise. 711 724 */ 712 - const struct acpm_handle *devm_acpm_get_by_phandle(struct device *dev, 713 - const char *property) 725 + const struct acpm_handle *devm_acpm_get_by_node(struct device *dev, 726 + struct device_node *np) 714 727 { 715 728 const struct acpm_handle **ptr, *handle; 716 729 ··· 718 731 if (!ptr) 719 732 return ERR_PTR(-ENOMEM); 720 733 721 - handle = acpm_get_by_phandle(dev, property); 734 + handle = acpm_get_by_node(dev, np); 722 735 if (!IS_ERR(handle)) { 723 736 *ptr = handle; 724 737 devres_add(dev, ptr); ··· 728 741 729 742 return handle; 730 743 } 744 + EXPORT_SYMBOL_GPL(devm_acpm_get_by_node); 731 745 732 746 static const struct acpm_match_data acpm_gs101 = { 733 747 .initdata_base = ACPM_GS101_INITDATA_BASE,
+4 -2
include/linux/firmware/samsung/exynos-acpm-protocol.h
··· 11 11 #include <linux/types.h> 12 12 13 13 struct acpm_handle; 14 + struct device_node; 14 15 15 16 struct acpm_pmic_ops { 16 17 int (*read_reg)(const struct acpm_handle *handle, ··· 45 44 46 45 struct device; 47 46 48 - const struct acpm_handle *devm_acpm_get_by_phandle(struct device *dev, 49 - const char *property); 47 + const struct acpm_handle *devm_acpm_get_by_node(struct device *dev, 48 + struct device_node *np); 49 + 50 50 #endif /* __EXYNOS_ACPM_PROTOCOL_H */