* [PATCH 07/16] net: phy: adin: make RGMII internal delays configurable
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190805165453.3989-1-alexandru.ardelean@analog.com>
The internal delays for the RGMII are configurable for both RX & TX. This
change adds support for configuring them via device-tree (or ACPI).
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/net/phy/adin.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index e3d2ff8cc09c..cb96d47d457e 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -5,6 +5,7 @@
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/kernel.h>
+#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -12,6 +13,8 @@
#include <linux/phy.h>
#include <linux/property.h>
+#include <dt-bindings/net/adin.h>
+
#define PHY_ID_ADIN1200 0x0283bc20
#define PHY_ID_ADIN1300 0x0283bc30
@@ -35,6 +38,12 @@
#define ADIN1300_INT_STATUS_REG 0x0019
#define ADIN1300_GE_RGMII_CFG_REG 0xff23
+#define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6)
+#define ADIN1300_GE_RGMII_RX_SEL(x) \
+ FIELD_PREP(ADIN1300_GE_RGMII_RX_MSK, x)
+#define ADIN1300_GE_RGMII_GTX_MSK GENMASK(5, 3)
+#define ADIN1300_GE_RGMII_GTX_SEL(x) \
+ FIELD_PREP(ADIN1300_GE_RGMII_GTX_MSK, x)
#define ADIN1300_GE_RGMII_RXID_EN BIT(2)
#define ADIN1300_GE_RGMII_TXID_EN BIT(1)
#define ADIN1300_GE_RGMII_EN BIT(0)
@@ -67,6 +76,32 @@ static int adin_get_phy_internal_mode(struct phy_device *phydev)
return -EINVAL;
}
+static void adin_config_rgmii_rx_internal_delay(struct phy_device *phydev,
+ int *reg)
+{
+ struct device *dev = &phydev->mdio.dev;
+ u32 val;
+
+ if (device_property_read_u32(dev, "adi,rx-internal-delay", &val))
+ val = ADIN1300_RGMII_2_00_NS;
+
+ *reg &= ADIN1300_GE_RGMII_RX_MSK;
+ *reg |= ADIN1300_GE_RGMII_RX_SEL(val);
+}
+
+static void adin_config_rgmii_tx_internal_delay(struct phy_device *phydev,
+ int *reg)
+{
+ struct device *dev = &phydev->mdio.dev;
+ u32 val;
+
+ if (device_property_read_u32(dev, "adi,tx-internal-delay", &val))
+ val = ADIN1300_RGMII_2_00_NS;
+
+ *reg &= ADIN1300_GE_RGMII_GTX_MSK;
+ *reg |= ADIN1300_GE_RGMII_GTX_SEL(val);
+}
+
static int adin_config_rgmii_mode(struct phy_device *phydev,
phy_interface_t intf)
{
@@ -86,6 +121,7 @@ static int adin_config_rgmii_mode(struct phy_device *phydev,
if (intf == PHY_INTERFACE_MODE_RGMII_ID ||
intf == PHY_INTERFACE_MODE_RGMII_RXID) {
reg |= ADIN1300_GE_RGMII_RXID_EN;
+ adin_config_rgmii_rx_internal_delay(phydev, ®);
} else {
reg &= ~ADIN1300_GE_RGMII_RXID_EN;
}
@@ -93,6 +129,7 @@ static int adin_config_rgmii_mode(struct phy_device *phydev,
if (intf == PHY_INTERFACE_MODE_RGMII_ID ||
intf == PHY_INTERFACE_MODE_RGMII_TXID) {
reg |= ADIN1300_GE_RGMII_TXID_EN;
+ adin_config_rgmii_tx_internal_delay(phydev, ®);
} else {
reg &= ~ADIN1300_GE_RGMII_TXID_EN;
}
--
2.20.1
^ permalink raw reply related
* [PATCH 06/16] net: phy: adin: support PHY mode converters
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190805165453.3989-1-alexandru.ardelean@analog.com>
Sometimes, the connection between a MAC and PHY is done via a
mode/interface converter. An example is a GMII-to-RGMII converter, which
would mean that the MAC operates in GMII mode while the PHY operates in
RGMII. In this case there is a discrepancy between what the MAC expects &
what the PHY expects and both need to be configured in their respective
modes.
Sometimes, this converter is specified via a board/system configuration (in
the device-tree for example). But, other times it can be left unspecified.
The use of these converters is common in boards that have FPGA on them.
This patch also adds support for a `adi,phy-mode-internal` property that
can be used in these (implicit convert) cases. The internal PHY mode will
be used to specify the correct register settings for the PHY.
`fwnode_handle` is used, since this property may be specified via ACPI as
well in other setups, but testing has been done in DT context.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/net/phy/adin.c | 39 ++++++++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index dbdb8f60741c..e3d2ff8cc09c 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/phy.h>
+#include <linux/property.h>
#define PHY_ID_ADIN1200 0x0283bc20
#define PHY_ID_ADIN1300 0x0283bc30
@@ -41,6 +42,31 @@
#define ADIN1300_GE_RMII_CFG_REG 0xff24
#define ADIN1300_GE_RMII_EN BIT(0)
+static int adin_get_phy_internal_mode(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ const char *pm;
+ int i;
+
+ if (device_property_read_string(dev, "adi,phy-mode-internal", &pm))
+ return phydev->interface;
+
+ /**
+ * Getting here assumes that there is converter in-between the actual
+ * PHY, for example a GMII-to-RGMII converter. In this case the MAC
+ * talks GMII and PHY talks RGMII, so the PHY needs to be set in RGMII
+ * while the MAC can work in GMII mode.
+ */
+
+ for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
+ if (!strcasecmp(pm, phy_modes(i)))
+ return i;
+
+ dev_err(dev, "Invalid value for 'phy-mode-internal': '%s'\n", pm);
+
+ return -EINVAL;
+}
+
static int adin_config_rgmii_mode(struct phy_device *phydev,
phy_interface_t intf)
{
@@ -105,7 +131,9 @@ static int adin_config_init(struct phy_device *phydev)
if (rc < 0)
return rc;
- interface = phydev->interface;
+ interface = adin_get_phy_internal_mode(phydev);
+ if (interface < 0)
+ return interface;
rc = adin_config_rgmii_mode(phydev, interface);
if (rc < 0)
@@ -115,8 +143,13 @@ static int adin_config_init(struct phy_device *phydev)
if (rc < 0)
return rc;
- dev_info(&phydev->mdio.dev, "PHY is using mode '%s'\n",
- phy_modes(phydev->interface));
+ if (phydev->interface == interface)
+ dev_info(&phydev->mdio.dev, "PHY is using mode '%s'\n",
+ phy_modes(phydev->interface));
+ else
+ dev_info(&phydev->mdio.dev,
+ "PHY is using mode '%s', MAC is using mode '%s'\n",
+ phy_modes(interface), phy_modes(phydev->interface));
return 0;
}
--
2.20.1
^ permalink raw reply related
* Re: [PATCH V13 12/12] PCI: tegra: Add Tegra194 PCIe support
From: Vidya Sagar @ 2019-08-05 16:54 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: bhelgaas, robh+dt, mark.rutland, thierry.reding, jonathanh,
kishon, catalin.marinas, will.deacon, jingoohan1,
gustavo.pimentel, digetx, mperttunen, linux-pci, devicetree,
linux-tegra, linux-kernel, linux-arm-kernel, kthota, mmaddireddy,
sagar.tv
In-Reply-To: <20190805140107.GA3850@e121166-lin.cambridge.arm.com>
On 8/5/2019 7:31 PM, Lorenzo Pieralisi wrote:
> On Fri, Aug 02, 2019 at 05:36:43PM +0530, Vidya Sagar wrote:
>> On 7/30/2019 9:19 PM, Lorenzo Pieralisi wrote:
>>> On Tue, Jul 23, 2019 at 08:14:08PM +0530, Vidya Sagar wrote:
>>>> On 7/16/2019 4:52 PM, Lorenzo Pieralisi wrote:
>>>>> On Sat, Jul 13, 2019 at 12:34:34PM +0530, Vidya Sagar wrote:
>>>>>
>>>>> [...]
>>>>>
>>>>>>>>>> +static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie,
>>>>>>>>>> + bool enable)
>>>>>>>>>> +{
>>>>>>>>>> + struct mrq_uphy_response resp;
>>>>>>>>>> + struct tegra_bpmp_message msg;
>>>>>>>>>> + struct mrq_uphy_request req;
>>>>>>>>>> + int err;
>>>>>>>>>> +
>>>>>>>>>> + if (pcie->cid == 5)
>>>>>>>>>> + return 0;
>>>>>>>>>
>>>>>>>>> What's wrong with cid == 5 ? Explain please.
>>>>>>>> Controller with ID=5 doesn't need any programming to enable it which is
>>>>>>>> done here through calling firmware API.
>>>>>>>>
>>>>>>>>>
>>>>>>>>>> + memset(&req, 0, sizeof(req));
>>>>>>>>>> + memset(&resp, 0, sizeof(resp));
>>>>>>>>>> +
>>>>>>>>>> + req.cmd = CMD_UPHY_PCIE_CONTROLLER_STATE;
>>>>>>>>>> + req.controller_state.pcie_controller = pcie->cid;
>>>>>>>>>> + req.controller_state.enable = enable;
>>>>>>>>>> +
>>>>>>>>>> + memset(&msg, 0, sizeof(msg));
>>>>>>>>>> + msg.mrq = MRQ_UPHY;
>>>>>>>>>> + msg.tx.data = &req;
>>>>>>>>>> + msg.tx.size = sizeof(req);
>>>>>>>>>> + msg.rx.data = &resp;
>>>>>>>>>> + msg.rx.size = sizeof(resp);
>>>>>>>>>> +
>>>>>>>>>> + if (irqs_disabled())
>>>>>>>>>
>>>>>>>>> Can you explain to me what this check is meant to achieve please ?
>>>>>>>> Firmware interface provides different APIs to be called when there are
>>>>>>>> no interrupts enabled in the system (noirq context) and otherwise
>>>>>>>> hence checking that situation here and calling appropriate API.
>>>>>>>
>>>>>>> That's what I am questioning. Being called from {suspend/resume}_noirq()
>>>>>>> callbacks (if that's the code path this check caters for) does not mean
>>>>>>> irqs_disabled() == true.
>>>>>> Agree.
>>>>>> Actually, I got a hint of having this check from the following.
>>>>>> Both tegra_bpmp_transfer_atomic() and tegra_bpmp_transfer() are indirectly
>>>>>> called by APIs registered with .master_xfer() and .master_xfer_atomic() hooks of
>>>>>> struct i2c_algorithm and the decision to call which one of these is made using the
>>>>>> following check in i2c-core.h file.
>>>>>> static inline bool i2c_in_atomic_xfer_mode(void)
>>>>>> {
>>>>>> return system_state > SYSTEM_RUNNING && irqs_disabled();
>>>>>> }
>>>>>> I think I should use this condition as is IIUC.
>>>>>> Please let me know if there are any concerns with this.
>>>>>
>>>>> It is not a concern, it is just that I don't understand how this code
>>>>> can be called with IRQs disabled, if you can give me an execution path I
>>>>> am happy to leave the check there. On top of that, when called from
>>>>> suspend NOIRQ context, it is likely to use the blocking API (because
>>>>> IRQs aren't disabled at CPU level) behind which there is most certainly
>>>>> an IRQ required to wake the thread up and if the IRQ in question was
>>>>> disabled in the suspend NOIRQ phase this code is likely to deadlock.
>>>>>
>>>>> I want to make sure we can justify adding this check, I do not
>>>>> want to add it because we think it can be needed when it may not
>>>>> be needed at all (and it gets copy and pasted over and over again
>>>>> in other drivers).
>>>> I had a discussion internally about this and the prescribed usage of these APIs
>>>> seem to be that
>>>> use tegra_bpmp_transfer() in .probe() and other paths where interrupts are
>>>> enabled as this API needs interrupts to be enabled for its working.
>>>> Use tegra_bpmp_transfer_atomic() surrounded by local_irq_save()/local_irq_restore()
>>>> in other paths where interrupt servicing is disabled.
>>>
>>> Why tegra_bpmp_transfer_atomic() needs IRQs to be disabled ? And why
>>> is it needed in this piece of code where IRQs are _never_ disabled
>>> at CPU level ?
>>>
>>> IRQs are enabled when you call a suspend_noirq() callback, so the
>>> blocking API can be used as long as the IRQ descriptor backing
>>> the IRQ that will wake-up the blocked call is marked as
>>> IRQF_NO_SUSPEND.
>>>
>>> The problem is not IRQs enabled/disabled at CPU level, the problem is
>>> the IRQ descriptor of the IRQ required to handle the blocking BPMP call,
>>> mark it as IRQF_NO_SUSPEND and remove the tegra_bpmp_transfer_atomic()
>>> call from this code (or please give me a concrete example pinpointing
>>> why it is needed).
>> Ideally, using tegra_bpmp_transfer() alone in all paths (.probe() as
>> well as .resume_noirq()) should have worked as the corresponding IRQ
>> is already flagged as IRQF_NO_SUSPEND, but, because of the way BPMP-FW
>> driver in kernel making its interface available through
>> .resume_early(), tegra_bpmp_transfer() wasn't working as expected and
>> I pushed a patch (CC'ing you) at
>> http://patchwork.ozlabs.org/patch/1140973/ to make it .resume_noirq()
>> from .resume_early(). With that in place, we can just use
>> tegra_bpmp_trasnfer(). I'll push a new patch with this change once my
>> BPMP-FW driver patch is approved.
>
> Does this leave you with a resume_noirq() callbacks ordering issue to
> sort out ?
Not really.
>
> a.k.a How will you guarantee that the BPMP will resume before the host
> bridge ?
It is already taken care of in the following way.
PCIe controller's device-tree node has an entry with a phandle of BPMP-FW's node
to get a handle of it and PCIe driver uses tegra_bpmp_get() API for that.
This API returns -EPROBE_DEFER if BPMP-FW's driver is not ready yet, which guarantees
that PCIe driver gets loaded only after BPMP-FW's driver and this order is followed
during noirq phase also.
>
> Thanks,
> Lorenzo
>
>> Thanks,
>> Vidya Sagar
>>>
>>> Thanks,
>>> Lorenzo
>>>
>>>> I'll go ahead and make next patch series with this if this looks fine to you.
>>>>
>>>>>
>>>>>>> Actually, if tegra_bpmp_transfer() requires IRQs to be enabled you may
>>>>>>> even end up in a situation where that blocking call does not wake up
>>>>>>> because the IRQ in question was disabled in the NOIRQ suspend/resume
>>>>>>> phase.
>>>>>>>
>>>>>>> [...]
>>>>>>>
>>>>>>>>>> +static int tegra_pcie_dw_probe(struct platform_device *pdev)
>>>>>>>>>> +{
>>>>>>>>>> + const struct tegra_pcie_soc *data;
>>>>>>>>>> + struct device *dev = &pdev->dev;
>>>>>>>>>> + struct resource *atu_dma_res;
>>>>>>>>>> + struct tegra_pcie_dw *pcie;
>>>>>>>>>> + struct resource *dbi_res;
>>>>>>>>>> + struct pcie_port *pp;
>>>>>>>>>> + struct dw_pcie *pci;
>>>>>>>>>> + struct phy **phys;
>>>>>>>>>> + char *name;
>>>>>>>>>> + int ret;
>>>>>>>>>> + u32 i;
>>>>>>>>>> +
>>>>>>>>>> + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
>>>>>>>>>> + if (!pcie)
>>>>>>>>>> + return -ENOMEM;
>>>>>>>>>> +
>>>>>>>>>> + pci = &pcie->pci;
>>>>>>>>>> + pci->dev = &pdev->dev;
>>>>>>>>>> + pci->ops = &tegra_dw_pcie_ops;
>>>>>>>>>> + pp = &pci->pp;
>>>>>>>>>> + pcie->dev = &pdev->dev;
>>>>>>>>>> +
>>>>>>>>>> + data = (struct tegra_pcie_soc *)of_device_get_match_data(dev);
>>>>>>>>>> + if (!data)
>>>>>>>>>> + return -EINVAL;
>>>>>>>>>> + pcie->mode = (enum dw_pcie_device_mode)data->mode;
>>>>>>>>>> +
>>>>>>>>>> + ret = tegra_pcie_dw_parse_dt(pcie);
>>>>>>>>>> + if (ret < 0) {
>>>>>>>>>> + dev_err(dev, "Failed to parse device tree: %d\n", ret);
>>>>>>>>>> + return ret;
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl");
>>>>>>>>>> + if (IS_ERR(pcie->pex_ctl_supply)) {
>>>>>>>>>> + dev_err(dev, "Failed to get regulator: %ld\n",
>>>>>>>>>> + PTR_ERR(pcie->pex_ctl_supply));
>>>>>>>>>> + return PTR_ERR(pcie->pex_ctl_supply);
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + pcie->core_clk = devm_clk_get(dev, "core");
>>>>>>>>>> + if (IS_ERR(pcie->core_clk)) {
>>>>>>>>>> + dev_err(dev, "Failed to get core clock: %ld\n",
>>>>>>>>>> + PTR_ERR(pcie->core_clk));
>>>>>>>>>> + return PTR_ERR(pcie->core_clk);
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>>>>>>>>>> + "appl");
>>>>>>>>>> + if (!pcie->appl_res) {
>>>>>>>>>> + dev_err(dev, "Failed to find \"appl\" region\n");
>>>>>>>>>> + return PTR_ERR(pcie->appl_res);
>>>>>>>>>> + }
>>>>>>>>>> + pcie->appl_base = devm_ioremap_resource(dev, pcie->appl_res);
>>>>>>>>>> + if (IS_ERR(pcie->appl_base))
>>>>>>>>>> + return PTR_ERR(pcie->appl_base);
>>>>>>>>>> +
>>>>>>>>>> + pcie->core_apb_rst = devm_reset_control_get(dev, "apb");
>>>>>>>>>> + if (IS_ERR(pcie->core_apb_rst)) {
>>>>>>>>>> + dev_err(dev, "Failed to get APB reset: %ld\n",
>>>>>>>>>> + PTR_ERR(pcie->core_apb_rst));
>>>>>>>>>> + return PTR_ERR(pcie->core_apb_rst);
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + phys = devm_kcalloc(dev, pcie->phy_count, sizeof(*phys), GFP_KERNEL);
>>>>>>>>>> + if (!phys)
>>>>>>>>>> + return PTR_ERR(phys);
>>>>>>>>>> +
>>>>>>>>>> + for (i = 0; i < pcie->phy_count; i++) {
>>>>>>>>>> + name = kasprintf(GFP_KERNEL, "p2u-%u", i);
>>>>>>>>>> + if (!name) {
>>>>>>>>>> + dev_err(dev, "Failed to create P2U string\n");
>>>>>>>>>> + return -ENOMEM;
>>>>>>>>>> + }
>>>>>>>>>> + phys[i] = devm_phy_get(dev, name);
>>>>>>>>>> + kfree(name);
>>>>>>>>>> + if (IS_ERR(phys[i])) {
>>>>>>>>>> + ret = PTR_ERR(phys[i]);
>>>>>>>>>> + dev_err(dev, "Failed to get PHY: %d\n", ret);
>>>>>>>>>> + return ret;
>>>>>>>>>> + }
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + pcie->phys = phys;
>>>>>>>>>> +
>>>>>>>>>> + dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
>>>>>>>>>> + if (!dbi_res) {
>>>>>>>>>> + dev_err(dev, "Failed to find \"dbi\" region\n");
>>>>>>>>>> + return PTR_ERR(dbi_res);
>>>>>>>>>> + }
>>>>>>>>>> + pcie->dbi_res = dbi_res;
>>>>>>>>>> +
>>>>>>>>>> + pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
>>>>>>>>>> + if (IS_ERR(pci->dbi_base))
>>>>>>>>>> + return PTR_ERR(pci->dbi_base);
>>>>>>>>>> +
>>>>>>>>>> + /* Tegra HW locates DBI2 at a fixed offset from DBI */
>>>>>>>>>> + pci->dbi_base2 = pci->dbi_base + 0x1000;
>>>>>>>>>> +
>>>>>>>>>> + atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>>>>>>>>>> + "atu_dma");
>>>>>>>>>> + if (!atu_dma_res) {
>>>>>>>>>> + dev_err(dev, "Failed to find \"atu_dma\" region\n");
>>>>>>>>>> + return PTR_ERR(atu_dma_res);
>>>>>>>>>> + }
>>>>>>>>>> + pcie->atu_dma_res = atu_dma_res;
>>>>>>>>>> + pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
>>>>>>>>>> + if (IS_ERR(pci->atu_base))
>>>>>>>>>> + return PTR_ERR(pci->atu_base);
>>>>>>>>>> +
>>>>>>>>>> + pcie->core_rst = devm_reset_control_get(dev, "core");
>>>>>>>>>> + if (IS_ERR(pcie->core_rst)) {
>>>>>>>>>> + dev_err(dev, "Failed to get core reset: %ld\n",
>>>>>>>>>> + PTR_ERR(pcie->core_rst));
>>>>>>>>>> + return PTR_ERR(pcie->core_rst);
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + pp->irq = platform_get_irq_byname(pdev, "intr");
>>>>>>>>>> + if (!pp->irq) {
>>>>>>>>>> + dev_err(dev, "Failed to get \"intr\" interrupt\n");
>>>>>>>>>> + return -ENODEV;
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + ret = devm_request_irq(dev, pp->irq, tegra_pcie_irq_handler,
>>>>>>>>>> + IRQF_SHARED, "tegra-pcie-intr", pcie);
>>>>>>>>>> + if (ret) {
>>>>>>>>>> + dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq, ret);
>>>>>>>>>> + return ret;
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + pcie->bpmp = tegra_bpmp_get(dev);
>>>>>>>>>> + if (IS_ERR(pcie->bpmp))
>>>>>>>>>> + return PTR_ERR(pcie->bpmp);
>>>>>>>>>> +
>>>>>>>>>> + platform_set_drvdata(pdev, pcie);
>>>>>>>>>> +
>>>>>>>>>> + if (pcie->mode == DW_PCIE_RC_TYPE) {
>>>>>>>>>> + ret = tegra_pcie_config_rp(pcie);
>>>>>>>>>> + if (ret && ret != -ENOMEDIUM)
>>>>>>>>>> + goto fail;
>>>>>>>>>> + else
>>>>>>>>>> + return 0;
>>>>>>>>>
>>>>>>>>> So if the link is not up we still go ahead and make probe
>>>>>>>>> succeed. What for ?
>>>>>>>> We may need root port to be available to support hot-plugging of
>>>>>>>> endpoint devices, so, we don't fail the probe.
>>>>>>>
>>>>>>> We need it or we don't. If you do support hotplugging of endpoint
>>>>>>> devices point me at the code, otherwise link up failure means
>>>>>>> failure to probe.
>>>>>> Currently hotplugging of endpoint is not supported, but it is one of
>>>>>> the use cases that we may add support for in future.
>>>>>
>>>>> You should elaborate on this, I do not understand what you mean,
>>>>> either the root port(s) supports hotplug or it does not.
>>>>>
>>>>>> But, why should we fail probe if link up doesn't happen? As such,
>>>>>> nothing went wrong in terms of root port initialization right? I
>>>>>> checked other DWC based implementations and following are not failing
>>>>>> the probe pci-dra7xx.c, pcie-armada8k.c, pcie-artpec6.c, pcie-histb.c,
>>>>>> pcie-kirin.c, pcie-spear13xx.c, pci-exynos.c, pci-imx6.c,
>>>>>> pci-keystone.c, pci-layerscape.c
>>>>>>
>>>>>> Although following do fail the probe if link is not up. pcie-qcom.c,
>>>>>> pcie-uniphier.c, pci-meson.c
>>>>>>
>>>>>> So, to me, it looks more like a choice we can make whether to fail the
>>>>>> probe or not and in this case we are choosing not to fail.
>>>>>
>>>>> I disagree. I had an offline chat with Bjorn and whether link-up should
>>>>> fail the probe or not depends on whether the root port(s) is hotplug
>>>>> capable or not and this in turn relies on the root port "Slot
>>>>> implemented" bit in the PCI Express capabilities register.
>>>>>
>>>>> It is a choice but it should be based on evidence.
>>>>>
>>>>> Lorenzo
>>>> With Bjorn's latest comment on top of this, I think we are good not to fail
>>>> the probe here.
>>>>
>>>> - Vidya Sagar
>>>>>
>>>>
>>
^ permalink raw reply
* [PATCH 05/16] net: phy: adin: configure RGMII/RMII/MII modes on config
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190805165453.3989-1-alexandru.ardelean@analog.com>
The ADIN1300 chip supports RGMII, RMII & MII modes. Default (if
unconfigured) is RGMII.
This change adds support for configuring these modes via the device
registers.
For RGMII with internal delays (modes RGMII_ID,RGMII_TXID, RGMII_RXID),
the default delay is 2 ns. This can be configurable and will be done in
a subsequent change.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/net/phy/adin.c | 79 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 3dd9fe50f4c8..dbdb8f60741c 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -33,14 +33,91 @@
ADIN1300_INT_HW_IRQ_EN)
#define ADIN1300_INT_STATUS_REG 0x0019
+#define ADIN1300_GE_RGMII_CFG_REG 0xff23
+#define ADIN1300_GE_RGMII_RXID_EN BIT(2)
+#define ADIN1300_GE_RGMII_TXID_EN BIT(1)
+#define ADIN1300_GE_RGMII_EN BIT(0)
+
+#define ADIN1300_GE_RMII_CFG_REG 0xff24
+#define ADIN1300_GE_RMII_EN BIT(0)
+
+static int adin_config_rgmii_mode(struct phy_device *phydev,
+ phy_interface_t intf)
+{
+ int reg;
+
+ reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_RGMII_CFG_REG);
+ if (reg < 0)
+ return reg;
+
+ if (!phy_interface_mode_is_rgmii(intf)) {
+ reg &= ~ADIN1300_GE_RGMII_EN;
+ goto write;
+ }
+
+ reg |= ADIN1300_GE_RGMII_EN;
+
+ if (intf == PHY_INTERFACE_MODE_RGMII_ID ||
+ intf == PHY_INTERFACE_MODE_RGMII_RXID) {
+ reg |= ADIN1300_GE_RGMII_RXID_EN;
+ } else {
+ reg &= ~ADIN1300_GE_RGMII_RXID_EN;
+ }
+
+ if (intf == PHY_INTERFACE_MODE_RGMII_ID ||
+ intf == PHY_INTERFACE_MODE_RGMII_TXID) {
+ reg |= ADIN1300_GE_RGMII_TXID_EN;
+ } else {
+ reg &= ~ADIN1300_GE_RGMII_TXID_EN;
+ }
+
+write:
+ return phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ ADIN1300_GE_RGMII_CFG_REG, reg);
+}
+
+static int adin_config_rmii_mode(struct phy_device *phydev,
+ phy_interface_t intf)
+{
+ int reg;
+
+ reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_RMII_CFG_REG);
+ if (reg < 0)
+ return reg;
+
+ if (intf != PHY_INTERFACE_MODE_RMII) {
+ reg &= ~ADIN1300_GE_RMII_EN;
+ goto write;
+ }
+
+ reg |= ADIN1300_GE_RMII_EN;
+
+write:
+ return phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ ADIN1300_GE_RMII_CFG_REG, reg);
+}
+
static int adin_config_init(struct phy_device *phydev)
{
- int rc;
+ phy_interface_t interface, rc;
rc = genphy_config_init(phydev);
if (rc < 0)
return rc;
+ interface = phydev->interface;
+
+ rc = adin_config_rgmii_mode(phydev, interface);
+ if (rc < 0)
+ return rc;
+
+ rc = adin_config_rmii_mode(phydev, interface);
+ if (rc < 0)
+ return rc;
+
+ dev_info(&phydev->mdio.dev, "PHY is using mode '%s'\n",
+ phy_modes(phydev->interface));
+
return 0;
}
--
2.20.1
^ permalink raw reply related
* [PATCH 04/16] net: phy: adin: add {write,read}_mmd hooks
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190805165453.3989-1-alexandru.ardelean@analog.com>
Both ADIN1200 & ADIN1300 support Clause 45 access.
The Extended Management Interface (EMI) registers are accessible via both
Clause 45 (at register MDIO_MMD_VEND1) and using Clause 22.
However, the Clause 22 MMD access operations differ from the implementation
in the kernel, in the sense that it uses registers ExtRegPtr (0x10) &
ExtRegData (0x11) to access Clause 45 & EMI registers.
The indirect access is done via the following mechanism (for both R/W):
1. Write the address of the register in the ExtRegPtr
2. Read/write the value of the register (written at ExtRegPtr)
This mechanism is needed to manage configuration of chip settings and to
access EEE registers (via Clause 22).
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/net/phy/adin.c | 46 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index b75c723bda79..3dd9fe50f4c8 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -14,6 +14,9 @@
#define PHY_ID_ADIN1200 0x0283bc20
#define PHY_ID_ADIN1300 0x0283bc30
+#define ADIN1300_MII_EXT_REG_PTR 0x10
+#define ADIN1300_MII_EXT_REG_DATA 0x11
+
#define ADIN1300_INT_MASK_REG 0x0018
#define ADIN1300_INT_MDIO_SYNC_EN BIT(9)
#define ADIN1300_INT_ANEG_STAT_CHNG_EN BIT(8)
@@ -63,6 +66,45 @@ static int adin_phy_config_intr(struct phy_device *phydev)
ADIN1300_INT_MASK_EN);
}
+static int adin_read_mmd(struct phy_device *phydev, int devad, u16 regnum)
+{
+ struct mii_bus *bus = phydev->mdio.bus;
+ int phy_addr = phydev->mdio.addr;
+ int err;
+
+ if (phydev->is_c45) {
+ u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
+
+ return __mdiobus_read(bus, phy_addr, addr);
+ }
+
+ err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR, regnum);
+ if (err)
+ return err;
+
+ return __mdiobus_read(bus, phy_addr, ADIN1300_MII_EXT_REG_DATA);
+}
+
+static int adin_write_mmd(struct phy_device *phydev, int devad, u16 regnum,
+ u16 val)
+{
+ struct mii_bus *bus = phydev->mdio.bus;
+ int phy_addr = phydev->mdio.addr;
+ int err;
+
+ if (phydev->is_c45) {
+ u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
+
+ return __mdiobus_write(bus, phy_addr, addr, val);
+ }
+
+ err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR, regnum);
+ if (err)
+ return err;
+
+ return __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_DATA, val);
+}
+
static struct phy_driver adin_driver[] = {
{
.phy_id = PHY_ID_ADIN1200,
@@ -77,6 +119,8 @@ static struct phy_driver adin_driver[] = {
.config_intr = adin_phy_config_intr,
.resume = genphy_resume,
.suspend = genphy_suspend,
+ .read_mmd = adin_read_mmd,
+ .write_mmd = adin_write_mmd,
},
{
.phy_id = PHY_ID_ADIN1300,
@@ -91,6 +135,8 @@ static struct phy_driver adin_driver[] = {
.config_intr = adin_phy_config_intr,
.resume = genphy_resume,
.suspend = genphy_suspend,
+ .read_mmd = adin_read_mmd,
+ .write_mmd = adin_write_mmd,
},
};
--
2.20.1
^ permalink raw reply related
* [PATCH 03/16] net: phy: adin: add support for interrupts
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190805165453.3989-1-alexandru.ardelean@analog.com>
This change adds support for enabling PHY interrupts that can be used by
the PHY framework to get signal for link/speed/auto-negotiation changes.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/net/phy/adin.c | 44 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index c100a0dd95cd..b75c723bda79 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -14,6 +14,22 @@
#define PHY_ID_ADIN1200 0x0283bc20
#define PHY_ID_ADIN1300 0x0283bc30
+#define ADIN1300_INT_MASK_REG 0x0018
+#define ADIN1300_INT_MDIO_SYNC_EN BIT(9)
+#define ADIN1300_INT_ANEG_STAT_CHNG_EN BIT(8)
+#define ADIN1300_INT_ANEG_PAGE_RX_EN BIT(6)
+#define ADIN1300_INT_IDLE_ERR_CNT_EN BIT(5)
+#define ADIN1300_INT_MAC_FIFO_OU_EN BIT(4)
+#define ADIN1300_INT_RX_STAT_CHNG_EN BIT(3)
+#define ADIN1300_INT_LINK_STAT_CHNG_EN BIT(2)
+#define ADIN1300_INT_SPEED_CHNG_EN BIT(1)
+#define ADIN1300_INT_HW_IRQ_EN BIT(0)
+#define ADIN1300_INT_MASK_EN \
+ (ADIN1300_INT_ANEG_STAT_CHNG_EN | ADIN1300_INT_ANEG_PAGE_RX_EN | \
+ ADIN1300_INT_LINK_STAT_CHNG_EN | ADIN1300_INT_SPEED_CHNG_EN | \
+ ADIN1300_INT_HW_IRQ_EN)
+#define ADIN1300_INT_STATUS_REG 0x0019
+
static int adin_config_init(struct phy_device *phydev)
{
int rc;
@@ -25,15 +41,40 @@ static int adin_config_init(struct phy_device *phydev)
return 0;
}
+static int adin_phy_ack_intr(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Clear pending interrupts. */
+ ret = phy_read(phydev, ADIN1300_INT_STATUS_REG);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int adin_phy_config_intr(struct phy_device *phydev)
+{
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ return phy_set_bits(phydev, ADIN1300_INT_MASK_REG,
+ ADIN1300_INT_MASK_EN);
+
+ return phy_clear_bits(phydev, ADIN1300_INT_MASK_REG,
+ ADIN1300_INT_MASK_EN);
+}
+
static struct phy_driver adin_driver[] = {
{
.phy_id = PHY_ID_ADIN1200,
.name = "ADIN1200",
.phy_id_mask = 0xfffffff0,
.features = PHY_BASIC_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
.config_init = adin_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = adin_phy_ack_intr,
+ .config_intr = adin_phy_config_intr,
.resume = genphy_resume,
.suspend = genphy_suspend,
},
@@ -42,9 +83,12 @@ static struct phy_driver adin_driver[] = {
.name = "ADIN1300",
.phy_id_mask = 0xfffffff0,
.features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
.config_init = adin_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = adin_phy_ack_intr,
+ .config_intr = adin_phy_config_intr,
.resume = genphy_resume,
.suspend = genphy_suspend,
},
--
2.20.1
^ permalink raw reply related
* [PATCH 02/16] net: phy: adin: hook genphy_{suspend,resume} into the driver
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190805165453.3989-1-alexandru.ardelean@analog.com>
The chip supports standard suspend/resume via BMCR reg.
Hook these functions into the `adin` driver.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/net/phy/adin.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 6a610d4563c3..c100a0dd95cd 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -34,6 +34,8 @@ static struct phy_driver adin_driver[] = {
.config_init = adin_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .resume = genphy_resume,
+ .suspend = genphy_suspend,
},
{
.phy_id = PHY_ID_ADIN1300,
@@ -43,6 +45,8 @@ static struct phy_driver adin_driver[] = {
.config_init = adin_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .resume = genphy_resume,
+ .suspend = genphy_suspend,
},
};
--
2.20.1
^ permalink raw reply related
* [PATCH 01/16] net: phy: adin: add support for Analog Devices PHYs
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190805165453.3989-1-alexandru.ardelean@analog.com>
This change adds support for Analog Devices Industrial Ethernet PHYs.
Particularly the PHYs this driver adds support for:
* ADIN1200 - Robust, Industrial, Low Power 10/100 Ethernet PHY
* ADIN1300 - Robust, Industrial, Low Latency 10/100/1000 Gigabit
Ethernet PHY
The 2 chips are pin & register compatible with one another. The main
difference being that ADIN1200 doesn't operate in gigabit mode.
The chips can be operated by the Generic PHY driver as well via the
standard IEEE PHY registers (0x0000 - 0x000F) which are supported by the
kernel as well. This assumes that configuration of the PHY has been done
required.
Configuration can also be done via registers, which will be implemented by
the driver in the next changes.
Datasheets:
https://www.analog.com/media/en/technical-documentation/data-sheets/ADIN1300.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ADIN1200.pdf
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
MAINTAINERS | 7 +++++
drivers/net/phy/Kconfig | 9 ++++++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/adin.c | 59 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 76 insertions(+)
create mode 100644 drivers/net/phy/adin.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ee663e0e2f2e..faf5723610c8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -938,6 +938,13 @@ S: Supported
F: drivers/mux/adgs1408.c
F: Documentation/devicetree/bindings/mux/adi,adgs1408.txt
+ANALOG DEVICES INC ADIN DRIVER
+M: Alexandru Ardelean <alexaundru.ardelean@analog.com>
+L: netdev@vger.kernel.org
+W: http://ez.analog.com/community/linux-device-drivers
+S: Supported
+F: drivers/net/phy/adin.c
+
ANALOG DEVICES INC ADIS DRIVER LIBRARY
M: Alexandru Ardelean <alexandru.ardelean@analog.com>
S: Supported
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 206d8650ee7f..5966d3413676 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -257,6 +257,15 @@ config SFP
depends on HWMON || HWMON=n
select MDIO_I2C
+config ADIN_PHY
+ tristate "Analog Devices Industrial Ethernet PHYs"
+ help
+ Adds support for the Analog Devices Industrial Ethernet PHYs.
+ Currently supports the:
+ - ADIN1200 - Robust,Industrial, Low Power 10/100 Ethernet PHY
+ - ADIN1300 - Robust,Industrial, Low Latency 10/100/1000 Gigabit
+ Ethernet PHY
+
config AMD_PHY
tristate "AMD PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index ba07c27e4208..a03437e091f3 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_SFP) += sfp.o
sfp-obj-$(CONFIG_SFP) += sfp-bus.o
obj-y += $(sfp-obj-y) $(sfp-obj-m)
+obj-$(CONFIG_ADIN_PHY) += adin.o
obj-$(CONFIG_AMD_PHY) += amd.o
aquantia-objs += aquantia_main.o
ifdef CONFIG_HWMON
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
new file mode 100644
index 000000000000..6a610d4563c3
--- /dev/null
+++ b/drivers/net/phy/adin.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * Driver for Analog Devices Industrial Ethernet PHYs
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#define PHY_ID_ADIN1200 0x0283bc20
+#define PHY_ID_ADIN1300 0x0283bc30
+
+static int adin_config_init(struct phy_device *phydev)
+{
+ int rc;
+
+ rc = genphy_config_init(phydev);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static struct phy_driver adin_driver[] = {
+ {
+ .phy_id = PHY_ID_ADIN1200,
+ .name = "ADIN1200",
+ .phy_id_mask = 0xfffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config_init = adin_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ },
+ {
+ .phy_id = PHY_ID_ADIN1300,
+ .name = "ADIN1300",
+ .phy_id_mask = 0xfffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config_init = adin_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ },
+};
+
+module_phy_driver(adin_driver);
+
+static struct mdio_device_id __maybe_unused adin_tbl[] = {
+ { PHY_ID_ADIN1200, 0xfffffff0 },
+ { PHY_ID_ADIN1300, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, adin_tbl);
+MODULE_DESCRIPTION("Analog Devices Industrial Ethernet PHY driver");
+MODULE_LICENSE("GPL");
--
2.20.1
^ permalink raw reply related
* [PATCH 00/16] net: phy: adin: add support for Analog Devices PHYs
From: Alexandru Ardelean @ 2019-08-05 16:54 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
This changeset adds support for Analog Devices Industrial Ethernet PHYs.
Particularly the PHYs this driver adds support for:
* ADIN1200 - Robust, Industrial, Low Power 10/100 Ethernet PHY
* ADIN1300 - Robust, Industrial, Low Latency 10/100/1000 Gigabit
Ethernet PHY
The 2 chips are pin & register compatible with one another. The main
difference being that ADIN1200 doesn't operate in gigabit mode.
The chips can be operated by the Generic PHY driver as well via the
standard IEEE PHY registers (0x0000 - 0x000F) which are supported by the
kernel as well. This assumes that configuration of the PHY has been done
completely in HW, according to spec, i.e. no extra SW configuration
required.
This changeset also implements the ability to configure the chips via SW
registers.
Datasheets:
https://www.analog.com/media/en/technical-documentation/data-sheets/ADIN1300.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ADIN1200.pdf
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
Alexandru Ardelean (16):
net: phy: adin: add support for Analog Devices PHYs
net: phy: adin: hook genphy_{suspend,resume} into the driver
net: phy: adin: add support for interrupts
net: phy: adin: add {write,read}_mmd hooks
net: phy: adin: configure RGMII/RMII/MII modes on config
net: phy: adin: support PHY mode converters
net: phy: adin: make RGMII internal delays configurable
net: phy: adin: make RMII fifo depth configurable
net: phy: adin: add support MDI/MDIX/Auto-MDI selection
net: phy: adin: add EEE translation layer for Clause 22
net: phy: adin: PHY reset mechanisms
net: phy: adin: read EEE setting from device-tree
net: phy: adin: implement Energy Detect Powerdown mode
net: phy: adin: make sure down-speed auto-neg is enabled
net: phy: adin: add ethtool get_stats support
dt-bindings: net: add bindings for ADIN PHY driver
.../devicetree/bindings/net/adi,adin.yaml | 93 +++
MAINTAINERS | 9 +
drivers/net/phy/Kconfig | 9 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/adin.c | 752 ++++++++++++++++++
include/dt-bindings/net/adin.h | 26 +
6 files changed, 890 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/adi,adin.yaml
create mode 100644 drivers/net/phy/adin.c
create mode 100644 include/dt-bindings/net/adin.h
--
2.20.1
^ permalink raw reply
* Re: [PATCH v7 0/3] add support for rng-seed
From: Hsin-Yi Wang @ 2019-08-05 16:34 UTC (permalink / raw)
To: moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
Cc: Rob Herring, devicetree, lkml, Frank Rowand, Catalin Marinas,
Will Deacon, Andrew Morton, Mike Rapoport, Ard Biesheuvel,
Miles Chen, James Morse, Andrew Murray, Mark Rutland, Jun Yao,
Yu Zhao, Robin Murphy, Laura Abbott, Stephen Boyd, Kees Cook
In-Reply-To: <20190703040135.169843-1-hsinyi@chromium.org>
Ping on the thread.
Should the series be proceeded?
Thanks
^ permalink raw reply
* Re: [PATCH v2] of/fdt: implement a "merge-cmdline" property
From: Rob Herring @ 2019-08-05 16:29 UTC (permalink / raw)
To: Daniel Gimpelevich; +Cc: devicetree, Paul Burton
In-Reply-To: <1565020400-25679-1-git-send-email-daniel@gimpelevich.san-francisco.ca.us>
On Mon, Aug 5, 2019 at 9:53 AM Daniel Gimpelevich
<daniel@gimpelevich.san-francisco.ca.us> wrote:
>
> Currently, "bootargs" supplied via the "chosen" node can be used only to
> supply a kernel command line as a whole. No mechanism exists in DT to add
> bootargs to the existing command line instead. This is needed in order to
> avoid having to update the bootloader or default bootloader config when
> upgrading to a DTB and kernel pair that requires bootargs not previously
> needed.
The DTB and kernel are not a pair. Or at least they shouldn't be. If
anything, the bootloader and DTB are a pair as those are the h/w
specific parts. If the DTB and kernel are a pair, then anything you
want to put into DTB can just be in the kernel. There's been some
attempts to rework the command line handling to be common and support
prepending and appending which could be useful here.
> One example use case is that OpenWrt currently supports four ARM devices by
> means of locally applying the previously rejected edition of this patch. So
> far, the patch has been used in production only on ARM, but architecture is
> not a distinction in the design.
Other distros support dozens of boards, so why haven't they ever
needed such a change?
> On MIPS, Commit 951d223 ("MIPS: Fix CONFIG_CMDLINE handling") currently
> prevents support of such a mechanism, so I am including a workaround, in
> anticipation of upcoming changes.
Like I said on irc, mixing this with the mess that is MIPS
bootloader-kernel interface generally and command line handling
specifically is not a path to upstream.
> Signed-off-by: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
> Fixes: 951d223 ("MIPS: Fix CONFIG_CMDLINE handling")
> References: https://patchwork.linux-mips.org/patch/17659/
> ---
> arch/mips/kernel/setup.c | 12 ++++++++----
> drivers/of/fdt.c | 9 +++++++--
> 2 files changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
> index ab349d2..9ce58f2 100644
> --- a/arch/mips/kernel/setup.c
> +++ b/arch/mips/kernel/setup.c
> @@ -725,7 +725,10 @@ static void __init arch_mem_init(char **cmdline_p)
> * CONFIG_CMDLINE ourselves below & don't want to duplicate its
> * content because repeating arguments can be problematic.
> */
> - strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
> + if (USE_DTB_CMDLINE)
> + strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
> + else
> + strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
>
> /* call board setup routine */
> plat_mem_setup();
> @@ -753,9 +756,10 @@ static void __init arch_mem_init(char **cmdline_p)
> #if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
> strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
> #else
> - if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
> - (USE_DTB_CMDLINE && !boot_command_line[0]))
> + if (USE_PROM_CMDLINE)
> strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
> + else if (!strcmp(boot_command_line, " "))
> + boot_command_line[0] = '\0';
>
> if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
> if (boot_command_line[0])
> @@ -764,7 +768,7 @@ static void __init arch_mem_init(char **cmdline_p)
> }
>
> #if defined(CONFIG_CMDLINE_BOOL)
> - if (builtin_cmdline[0]) {
> + if (builtin_cmdline[0] && strcmp(boot_command_line, builtin_cmdline)) {
> if (boot_command_line[0])
> strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
> strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> index 9cdf14b..08c25eb 100644
> --- a/drivers/of/fdt.c
> +++ b/drivers/of/fdt.c
> @@ -1055,8 +1055,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
>
> /* Retrieve command line */
> p = of_get_flat_dt_prop(node, "bootargs", &l);
> - if (p != NULL && l > 0)
> - strlcpy(data, p, min(l, COMMAND_LINE_SIZE));
> + if (p != NULL && l > 0) {
> + if (!of_get_flat_dt_prop(node, "merge-cmdline", NULL))
This is worse than the original proposal because 'merge' is not clear
what it does compared to 'append' and how does 'cmdline' relate to
'bootargs'.
> + *(char *)data = '\0';
> + if (*(char *)data)
> + strlcat(data, " ", COMMAND_LINE_SIZE);
> + strlcat(data, p, min(l + strlen(data), COMMAND_LINE_SIZE));
> + }
>
> /*
> * CONFIG_CMDLINE is meant to be a default in case nothing else
> --
> 1.9.1
>
^ permalink raw reply
* [RFC PATCH 1/2] dt-bindings: net: macb: Add new property for PS SGMII only
From: Harini Katakam @ 2019-08-05 16:10 UTC (permalink / raw)
To: Andrew Lunn
Cc: Harini Katakam, Nicolas Ferre, David Miller, Claudiu Beznea,
Rob Herring, Mark Rutland, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Michal Simek,
devicetree@vger.kernel.org
In-Reply-To: <CAFcVECLUNYRC-iZbKvvq2_XMLfXg7E10yAU5J_8GaEB3ExWRxg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1426 bytes --]
Hi Andrew,
On Mon, Aug 5, 2019 at 8:06 PM Harini Katakam <harinik@xilinx.com> wrote:
>
> Hi Andrew,
>
> On Mon, Aug 5, 2019 at 7:00 PM Andrew Lunn <andrew@lunn.ch> wrote:
> >
> > On Mon, Aug 05, 2019 at 11:45:05AM +0530, Harini Katakam wrote:
> > > Hi Andrew,
> > >
> > > On Sun, Aug 4, 2019 at 8:26 PM Andrew Lunn <andrew@lunn.ch> wrote:
> > > >
> > > > On Wed, Jul 31, 2019 at 03:10:32PM +0530, Harini Katakam wrote:
> > > > > Add a new property to indicate when PS SGMII is used with NO
> > > > > external PHY on board.
> > > >
> > > > Hi Harini
> > > >
> > > > What exactly is you use case? Are you connecting to a Ethernet
switch?
> > > > To an SFP cage with a copper module?
> > >
> > > Yes, an SFP cage is the common HW target for this patch.
> >
> > Hi Harini
> >
> > So you have a copper PHY in the SFP cage. It will talk SGMII
> > signalling to your PS SGMII. When that signalling is complete i would
> > expect the MAC to raise an interrupt, just as if the SGMII PHY was
> > soldered on the board. So i don't see why you need this polling?
> >
>
> Thanks. Sorry, I overlooked this interrupt. Let me try that.
Even with the use of this interrupt, the link status actions (link print and
netif ops) will still be required. And also the need for macb_open to
proceed without phydev. Could you please let me know if that is acceptable
to patch or if there's a cleaner way to
report this link status?
Regards,
Harini
[-- Attachment #2: Type: text/html, Size: 1929 bytes --]
^ permalink raw reply
* Re: [PATCH 3/8] of/fdt: add function to get the SoC wide DMA addressable memory size
From: Nicolas Saenz Julienne @ 2019-08-05 16:03 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon
Cc: Christoph Hellwig, wahrenst, Marc Zyngier, Robin Murphy,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
devicetree, Linux IOMMU, linux-mm, Frank Rowand, phill,
Florian Fainelli, linux-kernel@vger.kernel.org, Eric Anholt,
Matthias Brugger, Andrew Morton, Marek Szyprowski,
moderated list:BROADCOM BCM2835 ARM ARCHITECTURE
In-Reply-To: <CAL_JsqKF5nh3hcdLTG5+6RU3_TnFrNX08vD6qZ8wawoA3WSRpA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3219 bytes --]
Hi Rob,
Thanks for the review!
On Fri, 2019-08-02 at 11:17 -0600, Rob Herring wrote:
> On Wed, Jul 31, 2019 at 9:48 AM Nicolas Saenz Julienne
> <nsaenzjulienne@suse.de> wrote:
> > Some SoCs might have multiple interconnects each with their own DMA
> > addressing limitations. This function parses the 'dma-ranges' on each of
> > them and tries to guess the maximum SoC wide DMA addressable memory
> > size.
> >
> > This is specially useful for arch code in order to properly setup CMA
> > and memory zones.
>
> We already have a way to setup CMA in reserved-memory, so why is this
> needed for that?
Correct me if I'm wrong but I got the feeling you got the point of the patch
later on.
> > Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
> > ---
> >
> > drivers/of/fdt.c | 72 ++++++++++++++++++++++++++++++++++++++++++
> > include/linux/of_fdt.h | 2 ++
> > 2 files changed, 74 insertions(+)
> >
> > diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> > index 9cdf14b9aaab..f2444c61a136 100644
> > --- a/drivers/of/fdt.c
> > +++ b/drivers/of/fdt.c
> > @@ -953,6 +953,78 @@ int __init early_init_dt_scan_chosen_stdout(void)
> > }
> > #endif
> >
> > +/**
> > + * early_init_dt_dma_zone_size - Look at all 'dma-ranges' and provide the
> > + * maximum common dmable memory size.
> > + *
> > + * Some devices might have multiple interconnects each with their own DMA
> > + * addressing limitations. For example the Raspberry Pi 4 has the
> > following:
> > + *
> > + * soc {
> > + * dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
> > + * [...]
> > + * }
> > + *
> > + * v3dbus {
> > + * dma-ranges = <0x00000000 0x0 0x00000000 0x3c000000>;
> > + * [...]
> > + * }
> > + *
> > + * scb {
> > + * dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
> > + * [...]
> > + * }
> > + *
> > + * Here the area addressable by all devices is [0x00000000-0x3bffffff].
> > Hence
> > + * the function will write in 'data' a size of 0x3c000000.
> > + *
> > + * Note that the implementation assumes all interconnects have the same
> > physical
> > + * memory view and that the mapping always start at the beginning of RAM.
>
> Not really a valid assumption for general code.
Fair enough. On my defence I settled on that assumption after grepping all dts
and being unable to find a board that behaved otherwise.
[...]
> It's possible to have multiple levels of nodes and dma-ranges. You need to
> handle that case too. Doing that and handling differing address translations
> will be complicated.
Understood.
> IMO, I'd just do:
>
> if (of_fdt_machine_is_compatible(blob, "brcm,bcm2711"))
> dma_zone_size = XX;
>
> 2 lines of code is much easier to maintain than 10s of incomplete code
> and is clearer who needs this. Maybe if we have dozens of SoCs with
> this problem we should start parsing dma-ranges.
FYI that's what arm32 is doing at the moment and was my first instinct. But it
seems that arm64 has been able to survive so far without any machine specific
code and I have the feeling Catalin and Will will not be happy about this
solution. Am I wrong?
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v4 1/2] dt-bindings: Add binding document for NOA1305
From: Jonathan Cameron @ 2019-08-05 15:57 UTC (permalink / raw)
To: Martyn Welch
Cc: Mark Rutland, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, linux-iio, linux-kernel, kernel,
devicetree, Rob Herring
In-Reply-To: <20190802114228.1278-1-martyn.welch@collabora.com>
On Fri, 2 Aug 2019 12:42:27 +0100
Martyn Welch <martyn.welch@collabora.com> wrote:
> Document the ON Semiconductor NOA1305 ambient light sensor devicetree
> bindings.
>
> Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
Applied to the togreg branch of iio.git and pushed out as testing.
Thanks,
Jonathan
> ---
>
> Changes:
> v2: Same as v1.
> v3: Same as v2.
> v4: Same as v3.
>
> .../bindings/iio/light/noa1305.yaml | 44 +++++++++++++++++++
> 1 file changed, 44 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/light/noa1305.yaml
>
> diff --git a/Documentation/devicetree/bindings/iio/light/noa1305.yaml b/Documentation/devicetree/bindings/iio/light/noa1305.yaml
> new file mode 100644
> index 000000000000..17e7f140b69b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/light/noa1305.yaml
> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/light/noa1305.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ON Semiconductor NOA1305 Ambient Light Sensor
> +
> +maintainers:
> + - Martyn Welch <martyn.welch@collabora.com>
> +
> +description: |
> + Ambient sensing with an i2c interface.
> +
> + https://www.onsemi.com/pub/Collateral/NOA1305-D.PDF
> +
> +properties:
> + compatible:
> + enum:
> + - onnn,noa1305
> +
> + reg:
> + maxItems: 1
> +
> + vin-supply:
> + description: Regulator that provides power to the sensor
> +
> +required:
> + - compatible
> + - reg
> +
> +examples:
> + - |
> + i2c {
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + light@39 {
> + compatible = "onnn,noa1305";
> + reg = <0x39>;
> + };
> + };
> +...
^ permalink raw reply
* Re: [PATCH v4 2/2] iio: light: noa1305: Add support for NOA1305
From: Jonathan Cameron @ 2019-08-05 15:57 UTC (permalink / raw)
To: Martyn Welch
Cc: Mark Rutland, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, linux-iio, linux-kernel, kernel,
devicetree, Sergei M
In-Reply-To: <20190802114228.1278-2-martyn.welch@collabora.com>
On Fri, 2 Aug 2019 12:42:28 +0100
Martyn Welch <martyn.welch@collabora.com> wrote:
> This driver adds the initial support for the ON Semiconductor
> NOA1305 Ambient Light Sensor.
>
> Originally written by Sergei Miroshnichenko. Found here:
> https://github.com/EmcraftSystems/linux-upstream/commit/196d6cf897e632d2cb82d45484bd7a1bfdd5b6d9
>
> Signed-off-by: Sergei M <fizik1@yandex.com>
> Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
One minor thing I'll fix up whilst applying.
Applied to the togreg branch of iio.git and pushed out as testing
to see if we missed anything!
Thanks,
Jonathan
> ---
>
> Changes:
> v2:
> - Correcting authorship and SOB.
> v3:
> - Improve register define naming.
> - Follow IIO convention of interleaving register bit definitions with
> register defintions.
> - Use proper endian swapping.
> - Process raw sensor count into Lux.
> - Avoid setting variables to zero when not needed.
> - Check return value of i2c writes.
> - Implement disabling of regulator as a devm action.
> - Remove excessive white spacing.
> v4:
> - Clean up returns
> - Remove redundant noa1305_remove()
> - Remove redundant interrupt configuration/disabling
> - Return raw value and scaling
>
> Note: Scaling added for all possible interation times to ensure the
> mechanism utilised would allow this, though chip currently
> statically configured to 800mS.
>
> drivers/iio/light/Kconfig | 10 ++
> drivers/iio/light/Makefile | 1 +
> drivers/iio/light/noa1305.c | 312 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 323 insertions(+)
> create mode 100644 drivers/iio/light/noa1305.c
>
> diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
> index 954c958cfc43..d1db0ec0d0f5 100644
> --- a/drivers/iio/light/Kconfig
> +++ b/drivers/iio/light/Kconfig
> @@ -309,6 +309,16 @@ config MAX44009
> To compile this driver as a module, choose M here:
> the module will be called max44009.
>
> +config NOA1305
> + tristate "ON Semiconductor NOA1305 ambient light sensor"
> + depends on I2C
Needs to select REGMAP_I2C I think. I'll add that if it's all I find.
> + help
> + Say Y here if you want to build support for the ON Semiconductor
> + NOA1305 ambient light sensor.
> +
> + To compile this driver as a module, choose M here:
> + The module will be called noa1305.
> +
> config OPT3001
> tristate "Texas Instruments OPT3001 Light Sensor"
> depends on I2C
> diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
> index e40794fbb435..00d1f9b98f39 100644
> --- a/drivers/iio/light/Makefile
> +++ b/drivers/iio/light/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_LTR501) += ltr501.o
> obj-$(CONFIG_LV0104CS) += lv0104cs.o
> obj-$(CONFIG_MAX44000) += max44000.o
> obj-$(CONFIG_MAX44009) += max44009.o
> +obj-$(CONFIG_NOA1305) += noa1305.o
> obj-$(CONFIG_OPT3001) += opt3001.o
> obj-$(CONFIG_PA12203001) += pa12203001.o
> obj-$(CONFIG_RPR0521) += rpr0521.o
> diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c
> new file mode 100644
> index 000000000000..b8758aa7b32a
> --- /dev/null
> +++ b/drivers/iio/light/noa1305.c
> @@ -0,0 +1,312 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Support for ON Semiconductor NOA1305 ambient light sensor
> + *
> + * Copyright (C) 2016 Emcraft Systems
> + * Copyright (C) 2019 Collabora Ltd.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define NOA1305_REG_POWER_CONTROL 0x0
> +#define NOA1305_POWER_CONTROL_DOWN 0x00
> +#define NOA1305_POWER_CONTROL_ON 0x08
> +#define NOA1305_REG_RESET 0x1
> +#define NOA1305_RESET_RESET 0x10
> +#define NOA1305_REG_INTEGRATION_TIME 0x2
> +#define NOA1305_INTEGR_TIME_800MS 0x00
> +#define NOA1305_INTEGR_TIME_400MS 0x01
> +#define NOA1305_INTEGR_TIME_200MS 0x02
> +#define NOA1305_INTEGR_TIME_100MS 0x03
> +#define NOA1305_INTEGR_TIME_50MS 0x04
> +#define NOA1305_INTEGR_TIME_25MS 0x05
> +#define NOA1305_INTEGR_TIME_12_5MS 0x06
> +#define NOA1305_INTEGR_TIME_6_25MS 0x07
> +#define NOA1305_REG_INT_SELECT 0x3
> +#define NOA1305_INT_SEL_ACTIVE_HIGH 0x01
> +#define NOA1305_INT_SEL_ACTIVE_LOW 0x02
> +#define NOA1305_INT_SEL_INACTIVE 0x03
> +#define NOA1305_REG_INT_THRESH_LSB 0x4
> +#define NOA1305_REG_INT_THRESH_MSB 0x5
> +#define NOA1305_REG_ALS_DATA_LSB 0x6
> +#define NOA1305_REG_ALS_DATA_MSB 0x7
> +#define NOA1305_REG_DEVICE_ID_LSB 0x8
> +#define NOA1305_REG_DEVICE_ID_MSB 0x9
> +
> +#define NOA1305_DEVICE_ID 0x0519
> +#define NOA1305_DRIVER_NAME "noa1305"
> +
> +struct noa1305_priv {
> + struct i2c_client *client;
> + struct regmap *regmap;
> + struct regulator *vin_reg;
> +};
> +
> +static int noa1305_measure(struct noa1305_priv *priv)
> +{
> + __le16 data;
> + int ret;
> +
> + ret = regmap_bulk_read(priv->regmap, NOA1305_REG_ALS_DATA_LSB, &data,
> + 2);
> + if (ret < 0)
> + return ret;
> +
> + return le16_to_cpu(data);
> +}
> +
> +static int noa1305_scale(struct noa1305_priv *priv, int *val, int *val2)
> +{
> + int data;
> + int ret;
> +
> + ret = regmap_read(priv->regmap, NOA1305_REG_INTEGRATION_TIME, &data);
> + if (ret < 0)
> + return ret;
> +
> + /*
> + * Lux = count / (<Integration Constant> * <Integration Time>)
> + *
> + * Integration Constant = 7.7
> + * Integration Time in Seconds
> + */
> + switch (data) {
> + case NOA1305_INTEGR_TIME_800MS:
> + *val = 100;
> + *val2 = 77 * 8;
> + break;
> + case NOA1305_INTEGR_TIME_400MS:
> + *val = 100;
> + *val2 = 77 * 4;
> + case NOA1305_INTEGR_TIME_200MS:
> + *val = 100;
> + *val2 = 77 * 2;
> + break;
> + case NOA1305_INTEGR_TIME_100MS:
> + *val = 100;
> + *val2 = 77;
> + break;
> + case NOA1305_INTEGR_TIME_50MS:
> + *val = 1000;
> + *val2 = 77 * 5;
> + break;
> + case NOA1305_INTEGR_TIME_25MS:
> + *val = 10000;
> + *val2 = 77 * 25;
> + break;
> + case NOA1305_INTEGR_TIME_12_5MS:
> + *val = 100000;
> + *val2 = 77 * 125;
> + break;
> + case NOA1305_INTEGR_TIME_6_25MS:
> + *val = 1000000;
> + *val2 = 77 * 625;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return IIO_VAL_FRACTIONAL;
> +}
> +
> +static const struct iio_chan_spec noa1305_channels[] = {
> + {
> + .type = IIO_LIGHT,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
> + }
> +};
> +
> +static int noa1305_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + int ret = -EINVAL;
> + struct noa1305_priv *priv = iio_priv(indio_dev);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + switch (chan->type) {
> + case IIO_LIGHT:
> + ret = noa1305_measure(priv);
> + if (ret < 0)
> + return ret;
> + *val = ret;
> + return IIO_VAL_INT;
> + default:
> + break;
> + }
> + break;
> + case IIO_CHAN_INFO_SCALE:
> + switch (chan->type) {
> + case IIO_LIGHT:
> + return noa1305_scale(priv, val, val2);
> + default:
> + break;
> + }
> + break;
> + default:
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static const struct iio_info noa1305_info = {
> + .read_raw = noa1305_read_raw,
> +};
> +
> +static bool noa1305_writable_reg(struct device *dev, unsigned int reg)
> +{
> + switch (reg) {
> + case NOA1305_REG_POWER_CONTROL:
> + case NOA1305_REG_RESET:
> + case NOA1305_REG_INTEGRATION_TIME:
> + case NOA1305_REG_INT_SELECT:
> + case NOA1305_REG_INT_THRESH_LSB:
> + case NOA1305_REG_INT_THRESH_MSB:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> +static const struct regmap_config noa1305_regmap_config = {
> + .name = NOA1305_DRIVER_NAME,
> + .reg_bits = 8,
> + .val_bits = 8,
> + .max_register = NOA1305_REG_DEVICE_ID_MSB,
> + .writeable_reg = noa1305_writable_reg,
> +};
> +
> +static void noa1305_reg_remove(void *data)
> +{
> + struct noa1305_priv *priv = data;
> +
> + regulator_disable(priv->vin_reg);
> +}
> +
> +static int noa1305_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct noa1305_priv *priv;
> + struct iio_dev *indio_dev;
> + struct regmap *regmap;
> + __le16 data;
> + unsigned int dev_id;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*priv));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + regmap = devm_regmap_init_i2c(client, &noa1305_regmap_config);
> + if (IS_ERR(regmap)) {
> + dev_err(&client->dev, "Regmap initialization failed.\n");
> + return PTR_ERR(regmap);
> + }
> +
> + priv = iio_priv(indio_dev);
> +
> + priv->vin_reg = devm_regulator_get(&client->dev, "vin");
> + if (IS_ERR(priv->vin_reg)) {
> + dev_err(&client->dev, "get regulator vin failed\n");
> + return PTR_ERR(priv->vin_reg);
> + }
> +
> + ret = regulator_enable(priv->vin_reg);
> + if (ret) {
> + dev_err(&client->dev, "enable regulator vin failed\n");
> + return ret;
> + }
> +
> + ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv);
> + if (ret) {
> + dev_err(&client->dev, "addition of devm action failed\n");
> + return ret;
> + }
> +
> + i2c_set_clientdata(client, indio_dev);
> + priv->client = client;
> + priv->regmap = regmap;
> +
> + ret = regmap_bulk_read(regmap, NOA1305_REG_DEVICE_ID_LSB, &data, 2);
> + if (ret < 0) {
> + dev_err(&client->dev, "ID reading failed: %d\n", ret);
> + return ret;
> + }
> +
> + dev_id = le16_to_cpu(data);
> + if (dev_id != NOA1305_DEVICE_ID) {
> + dev_err(&client->dev, "Unknown device ID: 0x%x\n", dev_id);
> + return -ENODEV;
> + }
> +
> + ret = regmap_write(regmap, NOA1305_REG_POWER_CONTROL,
> + NOA1305_POWER_CONTROL_ON);
> + if (ret < 0) {
> + dev_err(&client->dev, "Enabling power control failed\n");
> + return ret;
> + }
> +
> + ret = regmap_write(regmap, NOA1305_REG_RESET, NOA1305_RESET_RESET);
> + if (ret < 0) {
> + dev_err(&client->dev, "Device reset failed\n");
> + return ret;
> + }
> +
> + ret = regmap_write(regmap, NOA1305_REG_INTEGRATION_TIME,
> + NOA1305_INTEGR_TIME_800MS);
> + if (ret < 0) {
> + dev_err(&client->dev, "Setting integration time failed\n");
> + return ret;
> + }
> +
> + indio_dev->dev.parent = &client->dev;
> + indio_dev->info = &noa1305_info;
> + indio_dev->channels = noa1305_channels;
> + indio_dev->num_channels = ARRAY_SIZE(noa1305_channels);
> + indio_dev->name = NOA1305_DRIVER_NAME;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> +
> + ret = devm_iio_device_register(&client->dev, indio_dev);
> + if (ret)
> + dev_err(&client->dev, "registering device failed\n");
> +
> + return ret;
> +}
> +
> +static const struct of_device_id noa1305_of_match[] = {
> + { .compatible = "onnn,noa1305" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, noa1305_of_match);
> +
> +static const struct i2c_device_id noa1305_ids[] = {
> + { "noa1305", 0 },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, noa1305_id);
> +
> +static struct i2c_driver noa1305_driver = {
> + .driver = {
> + .name = NOA1305_DRIVER_NAME,
> + .of_match_table = noa1305_of_match,
> + },
> + .probe = noa1305_probe,
> + .id_table = noa1305_ids,
> +};
> +
> +module_i2c_driver(noa1305_driver);
> +
> +MODULE_AUTHOR("Sergei Miroshnichenko <sergeimir@emcraft.com>");
> +MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.com");
> +MODULE_DESCRIPTION("ON Semiconductor NOA1305 ambient light sensor");
> +MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCHv2] drivers/amba: add reset control to primecell probe
From: Rob Herring @ 2019-08-05 15:54 UTC (permalink / raw)
To: Dinh Nguyen
Cc: devicetree, linux-kernel@vger.kernel.org, Frank Rowand, Kees Cook,
Anton Vorontsov, Colin Cross, Tony Luck
In-Reply-To: <20190805145211.23161-1-dinguyen@kernel.org>
On Mon, Aug 5, 2019 at 8:52 AM Dinh Nguyen <dinguyen@kernel.org> wrote:
>
> The primecell controller on some SoCs, i.e. SoCFPGA, is held in reset by
> default. Until recently, the DMA controller was brought out of reset by the
> bootloader(i.e. U-Boot). But a recent change in U-Boot, the peripherals that
> are not used are held in reset and are left to Linux to bring them out of
> reset.
>
> Add a mechanism for getting the reset property and de-assert the primecell
> module from reset if found. This is a not a hard fail if the reset property
> is not present in the device tree node, so the driver will continue to probe.
>
> Because there are different variants of the controller that may have multiple
> reset signals, the code will find all reset(s) specified and de-assert them.
>
> Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
> ---
> v2: move reset control to bus code
> find all reset properties and de-assert them
> ---
> drivers/amba/bus.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
> index 100e798a5c82..75e18b9e4808 100644
> --- a/drivers/amba/bus.c
> +++ b/drivers/amba/bus.c
> @@ -18,6 +18,7 @@
> #include <linux/limits.h>
> #include <linux/clk/clk-conf.h>
> #include <linux/platform_device.h>
> +#include <linux/reset.h>
>
> #include <asm/irq.h>
>
> @@ -401,6 +402,18 @@ static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
> ret = amba_get_enable_pclk(dev);
> if (ret == 0) {
> u32 pid, cid;
> + int count;
> + struct reset_control *rstc;
> +
> + /*
> + * Find reset control(s) of the amba bus and de-assert them.
> + */
> + count = reset_control_get_count(&dev->dev);
> + while (count > 0) {
> + rstc = of_reset_control_get_shared_by_index(dev->dev.of_node, count - 1);
> + reset_control_deassert(rstc);
> + count--;
> + }
Aren't you going to need a put somewhere?
And then there's the fun possibility of deferred probe which could
happen on any of the resets.
Rob
^ permalink raw reply
* [PATCH v2] of/fdt: implement a "merge-cmdline" property
From: Daniel Gimpelevich @ 2019-08-05 15:53 UTC (permalink / raw)
To: devicetree; +Cc: Paul Burton
Currently, "bootargs" supplied via the "chosen" node can be used only to
supply a kernel command line as a whole. No mechanism exists in DT to add
bootargs to the existing command line instead. This is needed in order to
avoid having to update the bootloader or default bootloader config when
upgrading to a DTB and kernel pair that requires bootargs not previously
needed.
One example use case is that OpenWrt currently supports four ARM devices by
means of locally applying the previously rejected edition of this patch. So
far, the patch has been used in production only on ARM, but architecture is
not a distinction in the design.
On MIPS, Commit 951d223 ("MIPS: Fix CONFIG_CMDLINE handling") currently
prevents support of such a mechanism, so I am including a workaround, in
anticipation of upcoming changes.
Signed-off-by: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
Fixes: 951d223 ("MIPS: Fix CONFIG_CMDLINE handling")
References: https://patchwork.linux-mips.org/patch/17659/
---
arch/mips/kernel/setup.c | 12 ++++++++----
drivers/of/fdt.c | 9 +++++++--
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index ab349d2..9ce58f2 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -725,7 +725,10 @@ static void __init arch_mem_init(char **cmdline_p)
* CONFIG_CMDLINE ourselves below & don't want to duplicate its
* content because repeating arguments can be problematic.
*/
- strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
+ if (USE_DTB_CMDLINE)
+ strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+ else
+ strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
/* call board setup routine */
plat_mem_setup();
@@ -753,9 +756,10 @@ static void __init arch_mem_init(char **cmdline_p)
#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
- if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
- (USE_DTB_CMDLINE && !boot_command_line[0]))
+ if (USE_PROM_CMDLINE)
strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+ else if (!strcmp(boot_command_line, " "))
+ boot_command_line[0] = '\0';
if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
if (boot_command_line[0])
@@ -764,7 +768,7 @@ static void __init arch_mem_init(char **cmdline_p)
}
#if defined(CONFIG_CMDLINE_BOOL)
- if (builtin_cmdline[0]) {
+ if (builtin_cmdline[0] && strcmp(boot_command_line, builtin_cmdline)) {
if (boot_command_line[0])
strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 9cdf14b..08c25eb 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -1055,8 +1055,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
/* Retrieve command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
- if (p != NULL && l > 0)
- strlcpy(data, p, min(l, COMMAND_LINE_SIZE));
+ if (p != NULL && l > 0) {
+ if (!of_get_flat_dt_prop(node, "merge-cmdline", NULL))
+ *(char *)data = '\0';
+ if (*(char *)data)
+ strlcat(data, " ", COMMAND_LINE_SIZE);
+ strlcat(data, p, min(l + strlen(data), COMMAND_LINE_SIZE));
+ }
/*
* CONFIG_CMDLINE is meant to be a default in case nothing else
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 1/4] iio: adc: ad7606: Add support for AD7606B ADC
From: Jonathan Cameron @ 2019-08-05 15:46 UTC (permalink / raw)
To: Beniamin Bia
Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
devel, linux-kernel, mark.rutland, robh+dt, devicetree, paulmck,
mchehab+samsung, linus.walleij, nicolas.ferre, biabeniamin,
Stefan Popa
In-Reply-To: <20190802100304.15899-1-beniamin.bia@analog.com>
On Fri, 2 Aug 2019 13:03:01 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:
> From: Stefan Popa <stefan.popa@analog.com>
>
> The AD7606B is a 16-bit ADC that supports simultaneous sampling of 8
> channels. It is pin compatible to AD7606, but adds extra modes by
> writing to the register map.
>
> The AD7606B can be configured to work in software mode by setting all
> oversampling pins to high. This mode is selected by default.
> The oversampling ratio is configured from the OS_MODE register (address
> 0x08) with the addition of OS=128 and OS=256 that were not available in
> hardware mode.
>
> The device is configured to output data on a single spi channel, but this
> configuration must be done right after restart. That is why the delay was
> removed for devices which doesn't require it.
>
> Moreover, in software mode, the range gpio has no longer its function.
> Instead, the scale can be configured individually for each channel from
> the RANGE_CH registers (address 0x03 to 0x06). Besides the already
> supported ±10 V and ±5 V ranges, software mode can also accommodate the
> ±2.5 V range.
>
> Signed-off-by: Stefan Popa <stefan.popa@analog.com>
> Co-developed-by: Beniamin Bia <beniamin.bia@analog.com>
> Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
This looks fine to me. I'll pick it up (if no other comments)
when you've tidied up the issues Rob raises for the DT bindings.
Thanks,
Jonathan
> ---
> drivers/iio/adc/ad7606.c | 13 ++++-
> drivers/iio/adc/ad7606.h | 4 ++
> drivers/iio/adc/ad7606_spi.c | 107 +++++++++++++++++++++++++++++++++++
> 3 files changed, 122 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
> index ed2d08437e5d..f5ba94c03a8d 100644
> --- a/drivers/iio/adc/ad7606.c
> +++ b/drivers/iio/adc/ad7606.c
> @@ -410,12 +410,19 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
> .oversampling_avail = ad7606_oversampling_avail,
> .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
> },
> + [ID_AD7606B] = {
> + .channels = ad7606_channels,
> + .num_channels = 9,
> + .oversampling_avail = ad7606_oversampling_avail,
> + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
> + },
> [ID_AD7616] = {
> .channels = ad7616_channels,
> .num_channels = 17,
> .oversampling_avail = ad7616_oversampling_avail,
> .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
> .os_req_reset = true,
> + .init_delay_ms = 15,
> },
> };
>
> @@ -631,8 +638,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
> dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
>
> /* AD7616 requires al least 15ms to reconfigure after a reset */
> - if (msleep_interruptible(15))
> - return -ERESTARTSYS;
> + if (st->chip_info->init_delay_ms) {
> + if (msleep_interruptible(st->chip_info->init_delay_ms))
> + return -ERESTARTSYS;
> + }
>
> st->write_scale = ad7606_write_scale_hw;
> st->write_os = ad7606_write_os_hw;
> diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
> index eeaaa8b905db..9350ef1f63b5 100644
> --- a/drivers/iio/adc/ad7606.h
> +++ b/drivers/iio/adc/ad7606.h
> @@ -46,6 +46,8 @@
> * oversampling ratios.
> * @oversampling_num number of elements stored in oversampling_avail array
> * @os_req_reset some devices require a reset to update oversampling
> + * @init_delay_ms required delay in miliseconds for initialization
> + * after a restart
> */
> struct ad7606_chip_info {
> const struct iio_chan_spec *channels;
> @@ -53,6 +55,7 @@ struct ad7606_chip_info {
> const unsigned int *oversampling_avail;
> unsigned int oversampling_num;
> bool os_req_reset;
> + unsigned long init_delay_ms;
> };
>
> /**
> @@ -155,6 +158,7 @@ enum ad7606_supported_device_ids {
> ID_AD7606_8,
> ID_AD7606_6,
> ID_AD7606_4,
> + ID_AD7606B,
> ID_AD7616,
> };
>
> diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
> index 98ed52b74507..070ee7e31e2c 100644
> --- a/drivers/iio/adc/ad7606_spi.c
> +++ b/drivers/iio/adc/ad7606_spi.c
> @@ -31,6 +31,20 @@
> /* The range of the channel is stored on 2 bits*/
> #define AD7616_RANGE_CH_MSK(ch) (0b11 << (((ch) & 0b11) * 2))
> #define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ((((ch) & 0b11)) * 2))
> +
> +#define AD7606_CONFIGURATION_REGISTER 0x02
> +#define AD7606_SINGLE_DOUT 0x0
> +
> +/*
> + * Range for AD7606B channels are stored in registers starting with address 0x3.
> + * Each register stores range for 2 channels(4 bits per channel).
> + */
> +#define AD7606_RANGE_CH_MSK(ch) (GENMASK(3, 0) << (4 * ((ch) & 0x1)))
> +#define AD7606_RANGE_CH_MODE(ch, mode) \
> + ((GENMASK(3, 0) & mode) << (4 * ((ch) & 0x1)))
> +#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1))
> +#define AD7606_OS_MODE 0x08
> +
> static const struct iio_chan_spec ad7616_sw_channels[] = {
> IIO_CHAN_SOFT_TIMESTAMP(16),
> AD7616_CHANNEL(0),
> @@ -51,6 +65,22 @@ static const struct iio_chan_spec ad7616_sw_channels[] = {
> AD7616_CHANNEL(15),
> };
>
> +static const struct iio_chan_spec ad7606B_sw_channels[] = {
> + IIO_CHAN_SOFT_TIMESTAMP(8),
> + AD7616_CHANNEL(0),
> + AD7616_CHANNEL(1),
> + AD7616_CHANNEL(2),
> + AD7616_CHANNEL(3),
> + AD7616_CHANNEL(4),
> + AD7616_CHANNEL(5),
> + AD7616_CHANNEL(6),
> + AD7616_CHANNEL(7),
> +};
> +
> +static const unsigned int ad7606B_oversampling_avail[9] = {
> + 1, 2, 4, 8, 16, 32, 64, 128, 256
> +};
> +
> static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp)
> {
> /*
> @@ -60,6 +90,16 @@ static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp)
> return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7);
> }
>
> +static u16 ad7606B_spi_rd_wr_cmd(int addr, char isWriteOp)
> +{
> + /*
> + * The address of register consists of one bit which
> + * specifies a read command placed bit 6, followed by
> + * 6 bits of address.
> + */
> + return (addr & 0x3F) | (((~isWriteOp) & 0x1) << 6);
> +}
> +
> static int ad7606_spi_read_block(struct device *dev,
> int count, void *buf)
> {
> @@ -169,6 +209,23 @@ static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val)
> AD7616_OS_MASK, val << 2);
> }
>
> +static int ad7606_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
> +{
> + struct ad7606_state *st = iio_priv(indio_dev);
> +
> + return ad7606_spi_write_mask(st,
> + AD7606_RANGE_CH_ADDR(ch),
> + AD7606_RANGE_CH_MSK(ch),
> + AD7606_RANGE_CH_MODE(ch, val));
> +}
> +
> +static int ad7606_write_os_sw(struct iio_dev *indio_dev, int val)
> +{
> + struct ad7606_state *st = iio_priv(indio_dev);
> +
> + return ad7606_spi_reg_write(st, AD7606_OS_MODE, val);
> +}
> +
> static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
> {
> struct ad7606_state *st = iio_priv(indio_dev);
> @@ -189,6 +246,42 @@ static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
> AD7616_BURST_MODE | AD7616_SEQEN_MODE);
> }
>
> +static int ad7606B_sw_mode_config(struct iio_dev *indio_dev)
> +{
> + struct ad7606_state *st = iio_priv(indio_dev);
> + unsigned long os[3] = {1};
> +
> + /*
> + * Software mode is enabled when all three oversampling
> + * pins are set to high. If oversampling gpios are defined
> + * in the device tree, then they need to be set to high,
> + * otherwise, they must be hardwired to VDD
> + */
> + if (st->gpio_os) {
> + gpiod_set_array_value(ARRAY_SIZE(os),
> + st->gpio_os->desc, st->gpio_os->info, os);
> + }
> + /* OS of 128 and 256 are available only in software mode */
> + st->oversampling_avail = ad7606B_oversampling_avail;
> + st->num_os_ratios = ARRAY_SIZE(ad7606B_oversampling_avail);
> +
> + st->write_scale = ad7606_write_scale_sw;
> + st->write_os = &ad7606_write_os_sw;
> +
> + /* Configure device spi to output on a single channel */
> + st->bops->reg_write(st,
> + AD7606_CONFIGURATION_REGISTER,
> + AD7606_SINGLE_DOUT);
> +
> + /*
> + * Scale can be configured individually for each channel
> + * in software mode.
> + */
> + indio_dev->channels = ad7606B_sw_channels;
> +
> + return 0;
> +}
> +
> static const struct ad7606_bus_ops ad7606_spi_bops = {
> .read_block = ad7606_spi_read_block,
> };
> @@ -202,6 +295,15 @@ static const struct ad7606_bus_ops ad7616_spi_bops = {
> .sw_mode_config = ad7616_sw_mode_config,
> };
>
> +static const struct ad7606_bus_ops ad7606B_spi_bops = {
> + .read_block = ad7606_spi_read_block,
> + .reg_read = ad7606_spi_reg_read,
> + .reg_write = ad7606_spi_reg_write,
> + .write_mask = ad7606_spi_write_mask,
> + .rd_wr_cmd = ad7606B_spi_rd_wr_cmd,
> + .sw_mode_config = ad7606B_sw_mode_config,
> +};
> +
> static int ad7606_spi_probe(struct spi_device *spi)
> {
> const struct spi_device_id *id = spi_get_device_id(spi);
> @@ -211,6 +313,9 @@ static int ad7606_spi_probe(struct spi_device *spi)
> case ID_AD7616:
> bops = &ad7616_spi_bops;
> break;
> + case ID_AD7606B:
> + bops = &ad7606B_spi_bops;
> + break;
> default:
> bops = &ad7606_spi_bops;
> break;
> @@ -226,6 +331,7 @@ static const struct spi_device_id ad7606_id_table[] = {
> { "ad7606-4", ID_AD7606_4 },
> { "ad7606-6", ID_AD7606_6 },
> { "ad7606-8", ID_AD7606_8 },
> + { "ad7606b", ID_AD7606B },
> { "ad7616", ID_AD7616 },
> {}
> };
> @@ -236,6 +342,7 @@ static const struct of_device_id ad7606_of_match[] = {
> { .compatible = "adi,ad7606-4" },
> { .compatible = "adi,ad7606-6" },
> { .compatible = "adi,ad7606-8" },
> + { .compatible = "adi,ad7606b" },
> { .compatible = "adi,ad7616" },
> { },
> };
^ permalink raw reply
* Re: [PATCH 5/6] tty: serial: Add linflexuart driver for S32V234
From: gregkh @ 2019-08-05 15:31 UTC (permalink / raw)
To: Stefan-gabriel Mirea
Cc: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
catalin.marinas@arm.com, will@kernel.org, shawnguo@kernel.org,
Leo Li, jslaby@suse.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
linux-serial@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
Larisa Ileana Grigore
In-Reply-To: <20190802194702.30249-6-stefan-gabriel.mirea@nxp.com>
On Fri, Aug 02, 2019 at 07:47:23PM +0000, Stefan-gabriel Mirea wrote:
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -293,4 +293,7 @@
> /* SiFive UART */
> #define PORT_SIFIVE_V0 120
>
> +/* Freescale Linflex UART */
> +#define PORT_LINFLEXUART 121
Do you really need this modified?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 15/16] net: phy: adin: add ethtool get_stats support
From: Andrew Lunn @ 2019-08-05 15:30 UTC (permalink / raw)
To: Alexandru Ardelean
Cc: netdev, devicetree, linux-kernel, davem, robh+dt, mark.rutland,
f.fainelli, hkallweit1
In-Reply-To: <20190805165453.3989-16-alexandru.ardelean@analog.com>
On Mon, Aug 05, 2019 at 07:54:52PM +0300, Alexandru Ardelean wrote:
> This change implements retrieving all the error counters from the PHY.
> The PHY supports several error counters/stats. The `Mean Square Errors`
> status values are only valie when a link is established, and shouldn't be
> incremented. These values characterize the quality of a signal.
I think you mean accumulated, not incremented?
>
> The rest of the error counters are self-clearing on read.
> Most of them are reports from the Frame Checker engine that the PHY has.
>
> Not retrieving the `LPI Wake Error Count Register` here, since that is used
> by the PHY framework to check for any EEE errors. And that register is
> self-clearing when read (as per IEEE spec).
>
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
> ---
> drivers/net/phy/adin.c | 108 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 108 insertions(+)
>
> diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
> index a1f3456a8504..04896547dac8 100644
> --- a/drivers/net/phy/adin.c
> +++ b/drivers/net/phy/adin.c
> @@ -103,6 +103,32 @@ static struct clause22_mmd_map clause22_mmd_map[] = {
> { MDIO_MMD_PCS, MDIO_PCS_EEE_WK_ERR, ADIN1300_LPI_WAKE_ERR_CNT_REG },
> };
>
> +struct adin_hw_stat {
> + const char *string;
> + u16 reg1;
> + u16 reg2;
> + bool do_not_inc;
do_not_accumulate? or reverse its meaning, clear_on_read?
Andrew
^ permalink raw reply
* Re: [PATCH/RFC 11/12] arm64: dts: renesas: cat874: Add definition for 12V regulator
From: Geert Uytterhoeven @ 2019-08-05 15:30 UTC (permalink / raw)
To: Fabrizio Castro
Cc: Laurent Pinchart, Geert Uytterhoeven, Kieran Bingham,
Jacopo Mondi, Rob Herring, Mark Rutland, Simon Horman,
Magnus Damm, linux-renesas-soc@vger.kernel.org,
devicetree@vger.kernel.org, Chris Paterson, Biju Das,
ebiharaml@si-linux.co.jp
In-Reply-To: <TY1PR01MB17702E7517D3EE5E48337DA8C0DA0@TY1PR01MB1770.jpnprd01.prod.outlook.com>
Hi Fabrizio,
On Mon, Aug 5, 2019 at 11:17 AM Fabrizio Castro
<fabrizio.castro@bp.renesas.com> wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Sent: 02 August 2019 09:30
> > Subject: Re: [PATCH/RFC 11/12] arm64: dts: renesas: cat874: Add definition for 12V regulator
> >
> > Hi Fabrizio,
> >
> > Thank you for the patch.
> >
> > On Fri, Aug 02, 2019 at 08:34:08AM +0100, Fabrizio Castro wrote:
> > > Power rail "D12.0V" comes straight from the power barrel connector,
> > > and it's used in both main board and sub board.
> > >
> > > Signed-off-by: Fabrizio Castro <fabrizio.castro@bp.renesas.com>
> >
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > I don't plan to take this in my tree without patch 12/12, so if you
> > think the rest of the series won't be ready in time for v5.4, feel free
> > to get this patch merged through Simon or Geert already.
>
> Geert, would you be happy to take this patch?
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v5.4.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH/RFC 10/12] arm64: dts: renesas: r8a774c0: Point LVDS0 to its companion LVDS1
From: Geert Uytterhoeven @ 2019-08-05 15:29 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Fabrizio Castro, Kieran Bingham, Jacopo Mondi, Rob Herring,
Mark Rutland, Simon Horman, Magnus Damm, Linux-Renesas,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Geert Uytterhoeven, Chris Paterson, Biju Das
In-Reply-To: <20190802091012.GN5008@pendragon.ideasonboard.com>
Hi Laurent,
On Fri, Aug 2, 2019 at 11:10 AM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Fri, Aug 02, 2019 at 11:03:54AM +0200, Geert Uytterhoeven wrote:
> > On Fri, Aug 2, 2019 at 10:27 AM Laurent Pinchart wrote:
> > > On Fri, Aug 02, 2019 at 08:34:07AM +0100, Fabrizio Castro wrote:
> > > > Add the new renesas,companion property to the LVDS0 node to point to the
> > > > companion LVDS encoder LVDS1.
> > > > Based on similar work from Laurent Pinchart for the r8a7799[05].
> > > >
> > > > Signed-off-by: Fabrizio Castro <fabrizio.castro@bp.renesas.com>
> > >
> > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >
> > > and taken in my tree.
> >
> > Shouldn't this go through renesas-devel and arm-soc?
>
> I'm collecting multimedia-related DT patches for v5.4, but if you or
> Simon want to take this patch, it will save me from sending a pull
> request, so please go ahead :-)
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v5.4.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 01/11] dt-bindings: mediatek: add support for mt6779 reference board
From: Rob Herring @ 2019-08-05 15:28 UTC (permalink / raw)
To: Mars Cheng
Cc: Matthias Brugger, CC Hwang, Loda Chou,
linux-kernel@vger.kernel.org,
moderated list:ARM/Mediatek SoC support, devicetree, wsd_upstream,
Wendell Lin, Ivan Tseng
In-Reply-To: <1564996320-10897-2-git-send-email-mars.cheng@mediatek.com>
On Mon, Aug 5, 2019 at 3:13 AM Mars Cheng <mars.cheng@mediatek.com> wrote:
>
> Update binding document for mt6779 reference board
>
> Signed-off-by: Mars Cheng <mars.cheng@mediatek.com>
> ---
> .../devicetree/bindings/arm/mediatek.yaml | 4 ++++
> 1 file changed, 4 insertions(+)
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 15/16] net: phy: adin: add ethtool get_stats support
From: Andrew Lunn @ 2019-08-05 15:28 UTC (permalink / raw)
To: Alexandru Ardelean
Cc: netdev, devicetree, linux-kernel, davem, robh+dt, mark.rutland,
f.fainelli, hkallweit1
In-Reply-To: <20190805165453.3989-16-alexandru.ardelean@analog.com>
> +struct adin_hw_stat {
> + const char *string;
> +static void adin_get_strings(struct phy_device *phydev, u8 *data)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(adin_hw_stats); i++) {
> + memcpy(data + i * ETH_GSTRING_LEN,
> + adin_hw_stats[i].string, ETH_GSTRING_LEN);
You define string as a char *. So it will be only as long as it should
be. However memcpy always copies ETH_GSTRING_LEN bytes, doing off the
end of the string and into whatever follows.
> + }
> +}
> +
> +static int adin_read_mmd_stat_regs(struct phy_device *phydev,
> + struct adin_hw_stat *stat,
> + u32 *val)
> +{
> + int ret;
> +
> + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, stat->reg1);
> + if (ret < 0)
> + return ret;
> +
> + *val = (ret & 0xffff);
> +
> + if (stat->reg2 == 0)
> + return 0;
> +
> + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, stat->reg2);
> + if (ret < 0)
> + return ret;
> +
> + *val <<= 16;
> + *val |= (ret & 0xffff);
Does the hardware have a snapshot feature? Is there a danger that
between the two reads stat->reg1 rolls over and you end up with too
big a value?
Andrew
^ permalink raw reply
* Re: [PATCH 2/4 v2] drm/panel: simple: Add TI nspire panel bindings
From: Rob Herring @ 2019-08-05 15:28 UTC (permalink / raw)
To: Linus Walleij
Cc: Fabian Vogt, Daniel Tang, dri-devel,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
devicetree
In-Reply-To: <20190805085847.25554-3-linus.walleij@linaro.org>
On Mon, Aug 5, 2019 at 2:59 AM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> Add bindings for the TI NSPIRE simple display panels.
>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> ChangeLog v1->v2:
> - New patch as bindings are required
> - Let's use YAML
> ---
> .../bindings/display/panel/ti,nspire.yaml | 36 +++++++++++++++++++
> 1 file changed, 36 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/panel/ti,nspire.yaml
>
> diff --git a/Documentation/devicetree/bindings/display/panel/ti,nspire.yaml b/Documentation/devicetree/bindings/display/panel/ti,nspire.yaml
> new file mode 100644
> index 000000000000..fa81602a922a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/ti,nspire.yaml
> @@ -0,0 +1,36 @@
> +# SPDX-License-Identifier: (GPL-2.0+ OR X11)
I think you want MIT rather than X11. However, the preference on new
bindings is (GPL-2.0-only OR BSD-2-Clause).
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/panel/ti,nspire.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Texas Instruments NSPIRE Display Panels
> +
> +maintainers:
> + - Linus Walleij <linus.walleij@linaro.org>
> +
> +properties:
> + compatible:
> + oneOf:
> + - items:
You can drop this. Just 'enum' is sufficient.
> + - enum:
> + - ti,nspire-cx-lcd-panel
> + - ti,nspire-classic-lcd-panel
> +
> +required:
> + - compatible
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + panel {
> + compatible = "ti,nspire-cx-lcd-panel";
> + ports {
> + port {
You need to capture that there's a single port in the schema. There's
not really a lot of examples for this yet, but you should add:
allOf:
- $ref: panel-common.yaml#
With a single port, you can drop 'ports' or you can keep it. If you do
the latter, then you need to define 'ports' and then 'port' in your
schema. The common schema is only sufficient if you have a single
'port' node otherwise you need to define what's under 'ports'.
Rob
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox