* Re: [PATCH] dt-bindings: Remove leading 0x from bindings notation
From: David Daney @ 2017-11-29 23:21 UTC (permalink / raw)
To: Mathieu Malaterre, Rob Herring
Cc: linux-kernel, devicetree, Marco Franchi, linux-mips
In-Reply-To: <20171129205515.9009-1-malat@debian.org>
On 11/29/2017 12:55 PM, Mathieu Malaterre wrote:
> Improve the binding example by removing all the leading 0x to fix the
> following dtc warnings:
>
> Warning (unit_address_format): Node /XXX unit name should not have leading "0x"
How does it fix the warnings? You are not changing the .dts files that
are compiled.
This may also cause the binding documentation to differ from the reality
of what the actual device trees contain.
>
> Converted using the following command:
>
> find Documentation/devicetree/bindings -name "*.txt" -exec sed -i -e 's/([^ ])\@0x([0-9a-f])/$1\@$2/g' {} +
>
> This is a follow up to commit 48c926cd3414
>
> Signed-off-by: Mathieu Malaterre <malat@debian.org>
> ---
> I've also checked using the original perl command that I did not introduce:
>
> Warning (unit_address_format): Node /XXX unit name should not have leading 0s
>
> Documentation/devicetree/bindings/arm/ccn.txt | 2 +-
> Documentation/devicetree/bindings/arm/omap/crossbar.txt | 2 +-
> .../devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt | 2 +-
> Documentation/devicetree/bindings/clock/axi-clkgen.txt | 2 +-
> .../devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt | 2 +-
> Documentation/devicetree/bindings/clock/exynos4-clock.txt | 2 +-
> Documentation/devicetree/bindings/clock/exynos5250-clock.txt | 2 +-
> Documentation/devicetree/bindings/clock/exynos5410-clock.txt | 2 +-
> Documentation/devicetree/bindings/clock/exynos5420-clock.txt | 2 +-
> Documentation/devicetree/bindings/clock/exynos5440-clock.txt | 2 +-
> .../devicetree/bindings/clock/ti-keystone-pllctrl.txt | 2 +-
> Documentation/devicetree/bindings/clock/zx296702-clk.txt | 4 ++--
> Documentation/devicetree/bindings/crypto/fsl-sec4.txt | 4 ++--
> .../devicetree/bindings/devfreq/event/rockchip-dfi.txt | 2 +-
> Documentation/devicetree/bindings/display/atmel,lcdc.txt | 4 ++--
> Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt | 4 ++--
> Documentation/devicetree/bindings/dma/zxdma.txt | 2 +-
> Documentation/devicetree/bindings/gpio/gpio-altera.txt | 2 +-
> Documentation/devicetree/bindings/i2c/i2c-jz4780.txt | 2 +-
> Documentation/devicetree/bindings/iio/pressure/hp03.txt | 2 +-
> .../devicetree/bindings/input/touchscreen/bu21013.txt | 2 +-
> .../devicetree/bindings/interrupt-controller/arm,gic.txt | 4 ++--
> .../bindings/interrupt-controller/img,meta-intc.txt | 2 +-
> .../bindings/interrupt-controller/img,pdc-intc.txt | 2 +-
> .../bindings/interrupt-controller/st,spear3xx-shirq.txt | 2 +-
> Documentation/devicetree/bindings/mailbox/altera-mailbox.txt | 6 +++---
> .../devicetree/bindings/mailbox/brcm,iproc-pdc-mbox.txt | 2 +-
> Documentation/devicetree/bindings/media/exynos5-gsc.txt | 2 +-
> Documentation/devicetree/bindings/media/mediatek-vcodec.txt | 2 +-
> Documentation/devicetree/bindings/media/rcar_vin.txt | 2 +-
> Documentation/devicetree/bindings/media/samsung-fimc.txt | 2 +-
> Documentation/devicetree/bindings/media/sh_mobile_ceu.txt | 2 +-
> Documentation/devicetree/bindings/media/video-interfaces.txt | 10 +++++-----
> .../devicetree/bindings/memory-controllers/ti/emif.txt | 2 +-
> .../devicetree/bindings/mfd/ti-keystone-devctrl.txt | 2 +-
> Documentation/devicetree/bindings/misc/brcm,kona-smc.txt | 2 +-
> Documentation/devicetree/bindings/mmc/brcm,kona-sdhci.txt | 2 +-
> Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt | 2 +-
> Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt | 4 ++--
> Documentation/devicetree/bindings/mtd/gpmc-nor.txt | 6 +++---
> Documentation/devicetree/bindings/mtd/mtk-nand.txt | 2 +-
> Documentation/devicetree/bindings/net/altera_tse.txt | 4 ++--
> Documentation/devicetree/bindings/net/mdio.txt | 2 +-
> Documentation/devicetree/bindings/net/socfpga-dwmac.txt | 2 +-
> Documentation/devicetree/bindings/nios2/nios2.txt | 2 +-
> Documentation/devicetree/bindings/pci/altera-pcie.txt | 2 +-
> Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | 2 +-
> Documentation/devicetree/bindings/pci/hisilicon-pcie.txt | 2 +-
> Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt | 2 +-
> .../devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt | 2 +-
> Documentation/devicetree/bindings/pinctrl/pinctrl-atlas7.txt | 4 ++--
> Documentation/devicetree/bindings/pinctrl/pinctrl-sirf.txt | 2 +-
> .../devicetree/bindings/pinctrl/rockchip,pinctrl.txt | 4 ++--
> Documentation/devicetree/bindings/regulator/regulator.txt | 2 +-
> Documentation/devicetree/bindings/serial/efm32-uart.txt | 2 +-
> .../devicetree/bindings/serio/allwinner,sun4i-ps2.txt | 2 +-
> .../devicetree/bindings/soc/ti/keystone-navigator-qmss.txt | 2 +-
> Documentation/devicetree/bindings/sound/adi,axi-i2s.txt | 2 +-
> Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt | 2 +-
> Documentation/devicetree/bindings/sound/ak4613.txt | 2 +-
> Documentation/devicetree/bindings/sound/ak4642.txt | 2 +-
> Documentation/devicetree/bindings/sound/max98371.txt | 2 +-
> Documentation/devicetree/bindings/sound/max9867.txt | 2 +-
> Documentation/devicetree/bindings/sound/renesas,fsi.txt | 2 +-
> Documentation/devicetree/bindings/sound/rockchip-spdif.txt | 2 +-
> Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt | 8 ++++----
> Documentation/devicetree/bindings/spi/efm32-spi.txt | 2 +-
> Documentation/devicetree/bindings/thermal/thermal.txt | 12 ++++++------
> Documentation/devicetree/bindings/ufs/ufs-qcom.txt | 4 ++--
> Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt | 2 +-
> Documentation/devicetree/bindings/usb/ehci-st.txt | 2 +-
> Documentation/devicetree/bindings/usb/ohci-st.txt | 2 +-
> .../devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt | 2 +-
> 73 files changed, 99 insertions(+), 99 deletions(-)
>
^ permalink raw reply
* Re: [PATCH 3/4] RFC: net: dsa: Add bindings for Realtek SMI DSAs
From: Linus Walleij @ 2017-11-29 23:19 UTC (permalink / raw)
To: Andrew Lunn
Cc: Vivien Didelot, Florian Fainelli, netdev-u79uwXL29TY76Z2rM5mHXA,
Antti Seppälä, Roman Yeryomin, Colin Leitner,
Gabor Juhos,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
In-Reply-To: <20171129215659.GC1706-g2DYL2Zd6BY@public.gmane.org>
On Wed, Nov 29, 2017 at 10:56 PM, Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org> wrote:
> I think the problem might be, you are using the DSA provided MDIO bus.
> The Marvell switches has a similar setup in terms of interrupts. The
> PHY interrupts appear within the switch. So i implemented an interrupt
> controller, just the same as you.
>
> The problem is, the DSA provided MDIO bus is not linked to device
> tree. So you cannot have phy nodes in device tree associated to it.
>
> What i did for the Marvell driver is that driver itself implements an
> MDIO bus (two actually in some chips), and the internal or external
> PHYs are placed on the switch drivers MDIO bus, rather than the DSA
> MDIO bus. The switch driver MDIO bus links to an mdio node in device
> tree. I can then have interrupt properties in the phys on this MDIO
> bus in device tree.
>
> What actually might make sense, is to have the DSA MDIO bus look
> inside the switches device tree node and see if there is an mdio
> node. If so allow dsa_switch_setup() to use of_mdiobus_register()
> instead of mdiobus_register().
Aha I think I see where my thinking went wrong.
I have been assuming (thought it was intuitive...) that ports and
PHYs are mapped 1:1.
So I assumed the port with reg = <N> is also the PHY with
reg = <N>
So naturally I added the PHY interrupt to the port node.
So you are saying that the PHY and the port are two
very disparate things in DSA terminology?
I guess all ports except the CPU port actually have
a 1:1 mapped PHY though, am I right?
Or are there in pracice things such that reg is different
on the port and the PHY connected to it? Then it makes
much sense to put an MDIO bus inside the switch DT
node and populate the PHY interrupts from there as you
say.
I can take a stab at fixing that if that is what we want.
Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 7/8] netdev: octeon-ethernet: Add Cavium Octeon III support.
From: David Daney @ 2017-11-29 23:04 UTC (permalink / raw)
To: Andrew Lunn, David Daney
Cc: Mark Rutland, linux-mips, devel, devicetree, netdev, linux-kernel,
ralf, Carlos Munoz, Rob Herring, Steven J. Hill,
Greg Kroah-Hartman, Florian Fainelli, James Hogan,
David S. Miller
In-Reply-To: <20171129225609.GE1706@lunn.ch>
On 11/29/2017 02:56 PM, Andrew Lunn wrote:
> On Tue, Nov 28, 2017 at 04:55:39PM -0800, David Daney wrote:
>> +static int bgx_probe(struct platform_device *pdev)
>> +{
>> + struct mac_platform_data platform_data;
>> + const __be32 *reg;
>> + u32 port;
>> + u64 addr;
>> + struct device_node *child;
>> + struct platform_device *new_dev;
>> + struct platform_device *pki_dev;
>> + int numa_node, interface;
>> + int i;
>> + int r = 0;
>> + char id[64];
>> + u64 data;
>> +
>> + reg = of_get_property(pdev->dev.of_node, "reg", NULL);
>> + addr = of_translate_address(pdev->dev.of_node, reg);
>> + interface = (addr >> 24) & 0xf;
>> + numa_node = (addr >> 36) & 0x7;
>
> Hi David
>
> You have these two a few times in the code. Maybe add a helper to do
> it? The NUMA one i assume could go somewhere in the SoC code?
>
Thanks for looking at it, I will try with helpers.
The rest of your comments below raise valid points, I will fix those too.
>> +static int bgx_mix_init_from_fdt(void)
>> +{
>> + struct device_node *node;
>> + struct device_node *parent = NULL;
>> + int mix = 0;
>
>> + /* Get the lmac index */
>> + reg = of_get_property(lmac_fdt_node, "reg", NULL);
>> + if (!reg)
>> + goto err;
>> +
>> + mix_port_lmacs[mix].lmac = *reg;
>
> I don't think of_get_property() deals with endianness. Is there any
> danger of this driver being used on hardware with the other endianness
> to what you have tested?
>
>> +/**
>> + * bgx_pki_init_from_param - Initialize the list of lmacs that connect to the
>> + * pki from information in the "pki_port" parameter.
>> + *
>> + * The pki_port parameter format is as follows:
>> + * pki_port=nbl
>> + * where:
>> + * n = node
>> + * b = bgx
>> + * l = lmac
>> + *
>> + * Commas must be used to separate multiple lmacs:
>> + * pki_port=000,100,110
>> + *
>> + * Asterisks (*) specify all possible characters in
>> + * the subset:
>> + * pki_port=00* (all lmacs of node0 bgx0).
>> + *
>> + * Missing lmacs identifiers default to all
>> + * possible characters in the subset:
>> + * pki_port=00 (all lmacs on node0 bgx0)
>> + *
>> + * Brackets ('[' and ']') specify the valid
>> + * characters in the subset:
>> + * pki_port=00[01] (lmac0 and lmac1 of node0 bgx0).
>> + *
>> + * Returns 0 if successful.
>> + * Returns <0 for error codes.
>
> I've not used kerneldoc much, but i suspect this is wrongly formated:
>
> https://www.kernel.org/doc/html/v4.9/kernel-documentation.html#function-documentation
>
>> +int bgx_port_ethtool_set_settings(struct net_device *netdev,
>> + struct ethtool_cmd *cmd)
>> +{
>> + struct bgx_port_priv *p = bgx_port_netdev2priv(netdev);
>> +
>> + if (!capable(CAP_NET_ADMIN))
>> + return -EPERM;
>
> Not required. The enforces this. See dev_ethtool()
>
>> +
>> + if (p->phydev)
>> + return phy_ethtool_sset(p->phydev, cmd);
>> +
>> + return -EOPNOTSUPP;
>> +}
>> +EXPORT_SYMBOL(bgx_port_ethtool_set_settings);
>> +
>> +int bgx_port_ethtool_nway_reset(struct net_device *netdev)
>> +{
>> + struct bgx_port_priv *p = bgx_port_netdev2priv(netdev);
>> +
>> + if (!capable(CAP_NET_ADMIN))
>> + return -EPERM;
>
> Also not needed.
>
>> +static void bgx_port_adjust_link(struct net_device *netdev)
>> +{
>> + struct bgx_port_priv *priv = bgx_port_netdev2priv(netdev);
>> + bool link_changed = false;
>> + unsigned int link;
>> + unsigned int speed;
>> + unsigned int duplex;
>> +
>> + mutex_lock(&priv->lock);
>> +
>> + if (!priv->phydev->link && priv->last_status.link)
>> + link_changed = true;
>> +
>> + if (priv->phydev->link &&
>> + (priv->last_status.link != priv->phydev->link ||
>> + priv->last_status.duplex != priv->phydev->duplex ||
>> + priv->last_status.speed != priv->phydev->speed))
>> + link_changed = true;
>> +
>> + link = priv->phydev->link;
>> + priv->last_status.link = priv->phydev->link;
>> +
>> + speed = priv->phydev->speed;
>> + priv->last_status.speed = priv->phydev->speed;
>> +
>> + duplex = priv->phydev->duplex;
>> + priv->last_status.duplex = priv->phydev->duplex;
>> +
>> + mutex_unlock(&priv->lock);
>> +
>> + if (link_changed) {
>> + struct port_status status;
>> +
>> + phy_print_status(priv->phydev);
>> +
>> + status.link = link ? 1 : 0;
>> + status.duplex = duplex;
>> + status.speed = speed;
>> + if (!link) {
>> + netif_carrier_off(netdev);
>> + /* Let TX drain. FIXME check that it is drained. */
>> + mdelay(50);
>> + }
>> + priv->set_link(priv, status);
>> + if (link)
>> + netif_carrier_on(netdev);
>
> The code should do netif_carrier_on/off for you. See phy_link_change()
>
>> +static void bgx_port_check_state(struct work_struct *work)
>> +{
>> + struct bgx_port_priv *priv;
>> + struct port_status status;
>> +
>> + priv = container_of(work, struct bgx_port_priv, dwork.work);
>> +
>> + status = priv->get_link(priv);
>> +
>> + if (!status.link &&
>> + priv->mode != PORT_MODE_SGMII && priv->mode != PORT_MODE_RGMII)
>> + bgx_port_init_xaui_link(priv);
>> +
>> + if (priv->last_status.link != status.link) {
>> + priv->last_status.link = status.link;
>> + if (status.link)
>> + netdev_info(priv->netdev, "Link is up - %d/%s\n",
>> + status.speed,
>> + status.duplex == DUPLEX_FULL ? "Full" : "Half");
>
> You already have phy_print_status() in bgx_port_adjust_link(). Do you need this here?
>
>> + else
>> + netdev_info(priv->netdev, "Link is down\n");
>> + }
>> +
>> + mutex_lock(&priv->lock);
>> + if (priv->work_queued)
>> + queue_delayed_work(check_state_wq, &priv->dwork, HZ);
>> + mutex_unlock(&priv->lock);
>> +}
>> +
>> +int bgx_port_enable(struct net_device *netdev)
>> +{
>
>
>> + } else {
>> + priv->phydev = of_phy_connect(netdev, priv->phy_np,
>> + bgx_port_adjust_link, 0, priv->phy_mode);
>> + if (!priv->phydev)
>> + return -ENODEV;
>> +
>> + netif_carrier_off(netdev);
>> +
>> + if (priv->phydev)
>
> You already checked this above.
>
>> + phy_start_aneg(priv->phydev);
>> + }
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(bgx_port_enable);
>> +
>> +int bgx_port_change_mtu(struct net_device *netdev, int new_mtu)
>> +{
>> + struct bgx_port_priv *priv = bgx_port_netdev2priv(netdev);
>> + int max_frame;
>> +
>> + if (new_mtu < 60 || new_mtu > 65392) {
>
> See dev_set_mtu(). If you have done your initialisation correctly, this
> won't happen.
>
>> +static int bgx_port_probe(struct platform_device *pdev)
>> +{
>> + switch (priv->mode) {
>> + case PORT_MODE_SGMII:
>> + if (priv->phy_np &&
>> + priv->phy_mode != PHY_INTERFACE_MODE_SGMII)
>> + dev_warn(&pdev->dev, "SGMII phy mode mismatch.\n");
>> + goto set_link_functions;
>> + case PORT_MODE_RGMII:
>> + if (priv->phy_np &&
>> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII &&
>> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_ID &&
>> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_RXID &&
>> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_TXID)
>
> phy_interface_mode_is_rgmii()
>
> More later, maybe.
>
> Andrew
>
^ permalink raw reply
* Re: [PATCH v4 7/8] netdev: octeon-ethernet: Add Cavium Octeon III support.
From: Andrew Lunn @ 2017-11-29 22:56 UTC (permalink / raw)
To: David Daney
Cc: linux-mips-6z/3iImG2C8G8FEW9MqTrA, ralf-6z/3iImG2C8G8FEW9MqTrA,
James Hogan, netdev-u79uwXL29TY76Z2rM5mHXA, David S. Miller,
Rob Herring, Mark Rutland, devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
Greg Kroah-Hartman, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Steven J. Hill, devicetree-u79uwXL29TY76Z2rM5mHXA,
Florian Fainelli, Carlos Munoz
In-Reply-To: <20171129005540.28829-8-david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
On Tue, Nov 28, 2017 at 04:55:39PM -0800, David Daney wrote:
> +static int bgx_probe(struct platform_device *pdev)
> +{
> + struct mac_platform_data platform_data;
> + const __be32 *reg;
> + u32 port;
> + u64 addr;
> + struct device_node *child;
> + struct platform_device *new_dev;
> + struct platform_device *pki_dev;
> + int numa_node, interface;
> + int i;
> + int r = 0;
> + char id[64];
> + u64 data;
> +
> + reg = of_get_property(pdev->dev.of_node, "reg", NULL);
> + addr = of_translate_address(pdev->dev.of_node, reg);
> + interface = (addr >> 24) & 0xf;
> + numa_node = (addr >> 36) & 0x7;
Hi David
You have these two a few times in the code. Maybe add a helper to do
it? The NUMA one i assume could go somewhere in the SoC code?
> +static int bgx_mix_init_from_fdt(void)
> +{
> + struct device_node *node;
> + struct device_node *parent = NULL;
> + int mix = 0;
> + /* Get the lmac index */
> + reg = of_get_property(lmac_fdt_node, "reg", NULL);
> + if (!reg)
> + goto err;
> +
> + mix_port_lmacs[mix].lmac = *reg;
I don't think of_get_property() deals with endianness. Is there any
danger of this driver being used on hardware with the other endianness
to what you have tested?
> +/**
> + * bgx_pki_init_from_param - Initialize the list of lmacs that connect to the
> + * pki from information in the "pki_port" parameter.
> + *
> + * The pki_port parameter format is as follows:
> + * pki_port=nbl
> + * where:
> + * n = node
> + * b = bgx
> + * l = lmac
> + *
> + * Commas must be used to separate multiple lmacs:
> + * pki_port=000,100,110
> + *
> + * Asterisks (*) specify all possible characters in
> + * the subset:
> + * pki_port=00* (all lmacs of node0 bgx0).
> + *
> + * Missing lmacs identifiers default to all
> + * possible characters in the subset:
> + * pki_port=00 (all lmacs on node0 bgx0)
> + *
> + * Brackets ('[' and ']') specify the valid
> + * characters in the subset:
> + * pki_port=00[01] (lmac0 and lmac1 of node0 bgx0).
> + *
> + * Returns 0 if successful.
> + * Returns <0 for error codes.
I've not used kerneldoc much, but i suspect this is wrongly formated:
https://www.kernel.org/doc/html/v4.9/kernel-documentation.html#function-documentation
> +int bgx_port_ethtool_set_settings(struct net_device *netdev,
> + struct ethtool_cmd *cmd)
> +{
> + struct bgx_port_priv *p = bgx_port_netdev2priv(netdev);
> +
> + if (!capable(CAP_NET_ADMIN))
> + return -EPERM;
Not required. The enforces this. See dev_ethtool()
> +
> + if (p->phydev)
> + return phy_ethtool_sset(p->phydev, cmd);
> +
> + return -EOPNOTSUPP;
> +}
> +EXPORT_SYMBOL(bgx_port_ethtool_set_settings);
> +
> +int bgx_port_ethtool_nway_reset(struct net_device *netdev)
> +{
> + struct bgx_port_priv *p = bgx_port_netdev2priv(netdev);
> +
> + if (!capable(CAP_NET_ADMIN))
> + return -EPERM;
Also not needed.
> +static void bgx_port_adjust_link(struct net_device *netdev)
> +{
> + struct bgx_port_priv *priv = bgx_port_netdev2priv(netdev);
> + bool link_changed = false;
> + unsigned int link;
> + unsigned int speed;
> + unsigned int duplex;
> +
> + mutex_lock(&priv->lock);
> +
> + if (!priv->phydev->link && priv->last_status.link)
> + link_changed = true;
> +
> + if (priv->phydev->link &&
> + (priv->last_status.link != priv->phydev->link ||
> + priv->last_status.duplex != priv->phydev->duplex ||
> + priv->last_status.speed != priv->phydev->speed))
> + link_changed = true;
> +
> + link = priv->phydev->link;
> + priv->last_status.link = priv->phydev->link;
> +
> + speed = priv->phydev->speed;
> + priv->last_status.speed = priv->phydev->speed;
> +
> + duplex = priv->phydev->duplex;
> + priv->last_status.duplex = priv->phydev->duplex;
> +
> + mutex_unlock(&priv->lock);
> +
> + if (link_changed) {
> + struct port_status status;
> +
> + phy_print_status(priv->phydev);
> +
> + status.link = link ? 1 : 0;
> + status.duplex = duplex;
> + status.speed = speed;
> + if (!link) {
> + netif_carrier_off(netdev);
> + /* Let TX drain. FIXME check that it is drained. */
> + mdelay(50);
> + }
> + priv->set_link(priv, status);
> + if (link)
> + netif_carrier_on(netdev);
The code should do netif_carrier_on/off for you. See phy_link_change()
> +static void bgx_port_check_state(struct work_struct *work)
> +{
> + struct bgx_port_priv *priv;
> + struct port_status status;
> +
> + priv = container_of(work, struct bgx_port_priv, dwork.work);
> +
> + status = priv->get_link(priv);
> +
> + if (!status.link &&
> + priv->mode != PORT_MODE_SGMII && priv->mode != PORT_MODE_RGMII)
> + bgx_port_init_xaui_link(priv);
> +
> + if (priv->last_status.link != status.link) {
> + priv->last_status.link = status.link;
> + if (status.link)
> + netdev_info(priv->netdev, "Link is up - %d/%s\n",
> + status.speed,
> + status.duplex == DUPLEX_FULL ? "Full" : "Half");
You already have phy_print_status() in bgx_port_adjust_link(). Do you need this here?
> + else
> + netdev_info(priv->netdev, "Link is down\n");
> + }
> +
> + mutex_lock(&priv->lock);
> + if (priv->work_queued)
> + queue_delayed_work(check_state_wq, &priv->dwork, HZ);
> + mutex_unlock(&priv->lock);
> +}
> +
> +int bgx_port_enable(struct net_device *netdev)
> +{
> + } else {
> + priv->phydev = of_phy_connect(netdev, priv->phy_np,
> + bgx_port_adjust_link, 0, priv->phy_mode);
> + if (!priv->phydev)
> + return -ENODEV;
> +
> + netif_carrier_off(netdev);
> +
> + if (priv->phydev)
You already checked this above.
> + phy_start_aneg(priv->phydev);
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(bgx_port_enable);
> +
> +int bgx_port_change_mtu(struct net_device *netdev, int new_mtu)
> +{
> + struct bgx_port_priv *priv = bgx_port_netdev2priv(netdev);
> + int max_frame;
> +
> + if (new_mtu < 60 || new_mtu > 65392) {
See dev_set_mtu(). If you have done your initialisation correctly, this
won't happen.
> +static int bgx_port_probe(struct platform_device *pdev)
> +{
> + switch (priv->mode) {
> + case PORT_MODE_SGMII:
> + if (priv->phy_np &&
> + priv->phy_mode != PHY_INTERFACE_MODE_SGMII)
> + dev_warn(&pdev->dev, "SGMII phy mode mismatch.\n");
> + goto set_link_functions;
> + case PORT_MODE_RGMII:
> + if (priv->phy_np &&
> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII &&
> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_ID &&
> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_RXID &&
> + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_TXID)
phy_interface_mode_is_rgmii()
More later, maybe.
Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [patch v12 2/4] drivers: jtag: Add Aspeed SoC 24xx and 25xx families JTAG master driver
From: Kun Yi @ 2017-11-29 22:51 UTC (permalink / raw)
To: Oleksandr Shamray
Cc: gregkh, arnd, system-sw-low-level, devicetree, jiri, vadimp,
linux-api, OpenBMC Maillist, linux-kernel, openocd-devel-owner,
mec, Jiri Pirko, robh+dt, linux-serial, tklauser, mchehab, davem,
linux-arm-kernel
In-Reply-To: <1510675867-24276-3-git-send-email-oleksandrs@mellanox.com>
Thanks for working on the driver, Oleksandr. I gave this a try on a
board with Aspeed 2520. One question below:
On Tue, Nov 14, 2017 at 8:11 AM, Oleksandr Shamray
<oleksandrs@mellanox.com> wrote:
> Driver adds support of Aspeed 2500/2400 series SOC JTAG master controller.
>
> Driver implements the following jtag ops:
> - freq_get;
> - freq_set;
> - status_get;
> - idle;
> - xfer;
>
> It has been tested on Mellanox system with BMC equipped with
> Aspeed 2520 SoC for programming CPLD devices.
>
> Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
> Signed-off-by: Jiri Pirko <jiri@mellanox.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> ---
> v11->v12
> Comments pointed by Chip Bilbrey <chip@bilbrey.org>
> - Remove access mode from xfer and idle transactions
> - Add new ioctl JTAG_SIOCMODE for set hw mode
>
> v10->v11
> v9->v10
> V8->v9
> Comments pointed by Arnd Bergmann <arnd@arndb.de>
> - add *data parameter to xfer function prototype
>
> v7->v8
> Comments pointed by Joel Stanley <joel.stan@gmail.com>
> - aspeed_jtag_init replace goto to return;
> - change input variables type from __u32 to u32
> in functios freq_get, freq_set, status_get
> - change sm_ variables type from char to u8
> - in jatg_init add disable clocks on error case
> - remove release_mem_region on error case
> - remove devm_free_irq on jtag_deinit
> - Fix misspelling Disabe/Disable
> - Change compatible string to ast2400 and ast2000
>
> v6->v7
> Notifications from kbuild test robot <lkp@intel.com>
> - Add include <linux/types.h> to jtag-asapeed.c
>
> v5->v6
> v4->v5
> Comments pointed by Arnd Bergmann <arnd@arndb.de>
> - Added HAS_IOMEM dependence in Kconfig to avoid
> "undefined reference to `devm_ioremap_resource'" error,
> because in some arch this not supported
>
> v3->v4
> Comments pointed by Arnd Bergmann <arnd@arndb.de>
> - change transaction pointer tdio type to __u64
> - change internal status type from enum to __u32
>
> v2->v3
>
> v1->v2
> Comments pointed by Greg KH <gregkh@linuxfoundation.org>
> - change license type from GPLv2/BSD to GPLv2
>
> Comments pointed by Neil Armstrong <narmstrong@baylibre.com>
> - Add clk_prepare_enable/clk_disable_unprepare in clock init/deinit
> - Change .compatible to soc-specific compatible names
> aspeed,aspeed4000-jtag/aspeed5000-jtag
> - Added dt-bindings
>
> Comments pointed by Arnd Bergmann <arnd@arndb.de>
> - Reorder functions and removed the forward declarations
> - Add static const qualifier to state machine states transitions
> - Change .compatible to soc-specific compatible names
> aspeed,aspeed4000-jtag/aspeed5000-jtag
> - Add dt-bindings
>
> Comments pointed by Randy Dunlap <rdunlap@infradead.org>
> - Change module name jtag-aspeed in description in Kconfig
>
> Comments pointed by kbuild test robot <lkp@intel.com>
> - Remove invalid include <asm/mach-types.h>
> - add resource_size instead of calculation
> ---
> drivers/jtag/Kconfig | 13 +
> drivers/jtag/Makefile | 1 +
> drivers/jtag/jtag-aspeed.c | 782 ++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 796 insertions(+), 0 deletions(-)
> create mode 100644 drivers/jtag/jtag-aspeed.c
>
> diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
> index 0fad1a3..098beb0 100644
> --- a/drivers/jtag/Kconfig
> +++ b/drivers/jtag/Kconfig
> @@ -14,3 +14,16 @@ menuconfig JTAG
>
> To compile this driver as a module, choose M here: the module will
> be called jtag.
> +
> +menuconfig JTAG_ASPEED
> + tristate "Aspeed SoC JTAG controller support"
> + depends on JTAG && HAS_IOMEM
> + ---help---
> + This provides a support for Aspeed JTAG device, equipped on
> + Aspeed SoC 24xx and 25xx families. Drivers allows programming
> + of hardware devices, connected to SoC through the JTAG interface.
> +
> + If you want this support, you should say Y here.
> +
> + To compile this driver as a module, choose M here: the module will
> + be called jtag-aspeed.
> diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
> index af37493..04a855e 100644
> --- a/drivers/jtag/Makefile
> +++ b/drivers/jtag/Makefile
> @@ -1 +1,2 @@
> obj-$(CONFIG_JTAG) += jtag.o
> +obj-$(CONFIG_JTAG_ASPEED) += jtag-aspeed.o
> diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c
> new file mode 100644
> index 0000000..a6e2417
> --- /dev/null
> +++ b/drivers/jtag/jtag-aspeed.c
> @@ -0,0 +1,782 @@
> +/*
> + * drivers/jtag/aspeed-jtag.c
> + *
> + * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
> + * Copyright (c) 2017 Oleksandr Shamray <oleksandrs@mellanox.com>
> + *
> + * Released under the GPLv2 only.
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/jtag.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <uapi/linux/jtag.h>
> +
> +#define ASPEED_JTAG_DATA 0x00
> +#define ASPEED_JTAG_INST 0x04
> +#define ASPEED_JTAG_CTRL 0x08
> +#define ASPEED_JTAG_ISR 0x0C
> +#define ASPEED_JTAG_SW 0x10
> +#define ASPEED_JTAG_TCK 0x14
> +#define ASPEED_JTAG_EC 0x18
> +
> +#define ASPEED_JTAG_DATA_MSB 0x01
> +#define ASPEED_JTAG_DATA_CHUNK_SIZE 0x20
> +
> +/* ASPEED_JTAG_CTRL: Engine Control */
> +#define ASPEED_JTAG_CTL_ENG_EN BIT(31)
> +#define ASPEED_JTAG_CTL_ENG_OUT_EN BIT(30)
> +#define ASPEED_JTAG_CTL_FORCE_TMS BIT(29)
> +#define ASPEED_JTAG_CTL_INST_LEN(x) ((x) << 20)
> +#define ASPEED_JTAG_CTL_LASPEED_INST BIT(17)
> +#define ASPEED_JTAG_CTL_INST_EN BIT(16)
> +#define ASPEED_JTAG_CTL_DR_UPDATE BIT(10)
> +#define ASPEED_JTAG_CTL_DATA_LEN(x) ((x) << 4)
> +#define ASPEED_JTAG_CTL_LASPEED_DATA BIT(1)
> +#define ASPEED_JTAG_CTL_DATA_EN BIT(0)
> +
> +/* ASPEED_JTAG_ISR : Interrupt status and enable */
> +#define ASPEED_JTAG_ISR_INST_PAUSE BIT(19)
> +#define ASPEED_JTAG_ISR_INST_COMPLETE BIT(18)
> +#define ASPEED_JTAG_ISR_DATA_PAUSE BIT(17)
> +#define ASPEED_JTAG_ISR_DATA_COMPLETE BIT(16)
> +#define ASPEED_JTAG_ISR_INST_PAUSE_EN BIT(3)
> +#define ASPEED_JTAG_ISR_INST_COMPLETE_EN BIT(2)
> +#define ASPEED_JTAG_ISR_DATA_PAUSE_EN BIT(1)
> +#define ASPEED_JTAG_ISR_DATA_COMPLETE_EN BIT(0)
> +#define ASPEED_JTAG_ISR_INT_EN_MASK GENMASK(3, 0)
> +#define ASPEED_JTAG_ISR_INT_MASK GENMASK(19, 16)
> +
> +/* ASPEED_JTAG_SW : Software Mode and Status */
> +#define ASPEED_JTAG_SW_MODE_EN BIT(19)
> +#define ASPEED_JTAG_SW_MODE_TCK BIT(18)
> +#define ASPEED_JTAG_SW_MODE_TMS BIT(17)
> +#define ASPEED_JTAG_SW_MODE_TDIO BIT(16)
> +
> +/* ASPEED_JTAG_TCK : TCK Control */
> +#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(10, 0)
> +#define ASPEED_JTAG_TCK_GET_DIV(x) ((x) & ASPEED_JTAG_TCK_DIVISOR_MASK)
> +
> +/* ASPEED_JTAG_EC : Controller set for go to IDLE */
> +#define ASPEED_JTAG_EC_GO_IDLE BIT(0)
> +
> +#define ASPEED_JTAG_IOUT_LEN(len) (ASPEED_JTAG_CTL_ENG_EN |\
> + ASPEED_JTAG_CTL_ENG_OUT_EN |\
> + ASPEED_JTAG_CTL_INST_LEN(len))
> +
> +#define ASPEED_JTAG_DOUT_LEN(len) (ASPEED_JTAG_CTL_ENG_EN |\
> + ASPEED_JTAG_CTL_ENG_OUT_EN |\
> + ASPEED_JTAG_CTL_DATA_LEN(len))
> +
> +#define ASPEED_JTAG_TCK_WAIT 10
> +#define ASPEED_JTAG_RESET_CNTR 10
> +
> +#define ASPEED_JTAG_NAME "jtag-aspeed"
> +
> +struct aspeed_jtag {
> + void __iomem *reg_base;
> + struct device *dev;
> + struct clk *pclk;
> + enum jtag_endstate status;
> + int irq;
> + u32 flag;
> + wait_queue_head_t jtag_wq;
> + u32 mode;
> +};
> +
> +static char *end_status_str[] = {"idle", "ir pause", "drpause"};
> +
> +static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg)
> +{
> + return readl(aspeed_jtag->reg_base + reg);
> +}
> +
> +static void
> +aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg)
> +{
> + writel(val, aspeed_jtag->reg_base + reg);
> +}
> +
> +static int aspeed_jtag_freq_set(struct jtag *jtag, u32 freq)
> +{
> + struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
> + unsigned long apb_frq;
> + u32 tck_val;
> + u16 div;
> +
> + apb_frq = clk_get_rate(aspeed_jtag->pclk);
> + div = (apb_frq % freq == 0) ? (apb_frq / freq) - 1 : (apb_frq / freq);
> + tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
> + aspeed_jtag_write(aspeed_jtag,
> + (tck_val & ASPEED_JTAG_TCK_DIVISOR_MASK) | div,
> + ASPEED_JTAG_TCK);
> + return 0;
> +}
> +
> +static int aspeed_jtag_freq_get(struct jtag *jtag, u32 *frq)
> +{
> + struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
> + u32 pclk;
> + u32 tck;
> +
> + pclk = clk_get_rate(aspeed_jtag->pclk);
> + tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
> + *frq = pclk / (ASPEED_JTAG_TCK_GET_DIV(tck) + 1);
> +
> + return 0;
> +}
> +
> +static int aspeed_jtag_mode_set(struct jtag *jtag, u32 mode)
> +{
> + struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
> +
> + aspeed_jtag->mode = mode;
> + return 0;
> +}
> +
> +static void aspeed_jtag_sw_delay(struct aspeed_jtag *aspeed_jtag, int cnt)
> +{
> + int i;
> +
> + for (i = 0; i < cnt; i++)
> + aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW);
> +}
> +
> +static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag,
> + u8 tms, u8 tdi)
> +{
> + char tdo = 0;
> +
> + /* TCK = 0 */
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
> + (tms * ASPEED_JTAG_SW_MODE_TMS) |
> + (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
> +
> + aspeed_jtag_sw_delay(aspeed_jtag, ASPEED_JTAG_TCK_WAIT);
> +
> + /* TCK = 1 */
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
> + ASPEED_JTAG_SW_MODE_TCK |
> + (tms * ASPEED_JTAG_SW_MODE_TMS) |
> + (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
> +
> + if (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) &
> + ASPEED_JTAG_SW_MODE_TDIO)
> + tdo = 1;
> +
> + aspeed_jtag_sw_delay(aspeed_jtag, ASPEED_JTAG_TCK_WAIT);
> +
> + /* TCK = 0 */
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
> + (tms * ASPEED_JTAG_SW_MODE_TMS) |
> + (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
> + return tdo;
> +}
> +
> +static void aspeed_jtag_wait_instruction_pause(struct aspeed_jtag *aspeed_jtag)
> +{
> + wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
> + ASPEED_JTAG_ISR_INST_PAUSE);
> + aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_PAUSE;
> +}
> +
> +static void
> +aspeed_jtag_wait_instruction_complete(struct aspeed_jtag *aspeed_jtag)
> +{
> + wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
> + ASPEED_JTAG_ISR_INST_COMPLETE);
> + aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_COMPLETE;
> +}
> +
> +static void
> +aspeed_jtag_wait_data_pause_complete(struct aspeed_jtag *aspeed_jtag)
> +{
> + wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
> + ASPEED_JTAG_ISR_DATA_PAUSE);
> + aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_PAUSE;
> +}
> +
> +static void aspeed_jtag_wait_data_complete(struct aspeed_jtag *aspeed_jtag)
> +{
> + wait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &
> + ASPEED_JTAG_ISR_DATA_COMPLETE);
> + aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_COMPLETE;
> +}
> +
> +static void aspeed_jtag_sm_cycle(struct aspeed_jtag *aspeed_jtag, const u8 *tms,
> + int len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++)
> + aspeed_jtag_tck_cycle(aspeed_jtag, tms[i], 0);
> +}
> +
> +static void aspeed_jtag_run_test_idle_sw(struct aspeed_jtag *aspeed_jtag,
> + struct jtag_run_test_idle *runtest)
> +{
> + static const u8 sm_pause_irpause[] = {1, 1, 1, 1, 0, 1, 0};
> + static const u8 sm_pause_drpause[] = {1, 1, 1, 0, 1, 0};
> + static const u8 sm_idle_irpause[] = {1, 1, 0, 1, 0};
> + static const u8 sm_idle_drpause[] = {1, 0, 1, 0};
> + static const u8 sm_pause_idle[] = {1, 1, 0};
> + int i;
> +
> + /* SW mode from idle/pause-> to pause/idle */
> + if (runtest->reset) {
> + for (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++)
> + aspeed_jtag_tck_cycle(aspeed_jtag, 1, 0);
> + }
> +
> + switch (aspeed_jtag->status) {
> + case JTAG_STATE_IDLE:
> + switch (runtest->endstate) {
> + case JTAG_STATE_PAUSEIR:
> + /* ->DRSCan->IRSCan->IRCap->IRExit1->PauseIR */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_idle_irpause,
> + sizeof(sm_idle_irpause));
> +
> + aspeed_jtag->status = JTAG_STATE_PAUSEIR;
> + break;
> + case JTAG_STATE_PAUSEDR:
> + /* ->DRSCan->DRCap->DRExit1->PauseDR */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_idle_drpause,
> + sizeof(sm_idle_drpause));
> +
> + aspeed_jtag->status = JTAG_STATE_PAUSEDR;
> + break;
> + case JTAG_STATE_IDLE:
> + /* IDLE */
> + aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);
> + aspeed_jtag->status = JTAG_STATE_IDLE;
> + break;
> + default:
> + break;
> + }
> + break;
> +
> + case JTAG_STATE_PAUSEIR:
> + /* Fall-through */
> + case JTAG_STATE_PAUSEDR:
> + /* From IR/DR Pause */
> + switch (runtest->endstate) {
> + case JTAG_STATE_PAUSEIR:
> + /*
> + * to Exit2 IR/DR->Updt IR/DR->DRSCan->IRSCan->IRCap->
> + * IRExit1->PauseIR
> + */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_irpause,
> + sizeof(sm_pause_irpause));
> +
> + aspeed_jtag->status = JTAG_STATE_PAUSEIR;
> + break;
> + case JTAG_STATE_PAUSEDR:
> + /*
> + * to Exit2 IR/DR->Updt IR/DR->DRSCan->DRCap->
> + * DRExit1->PauseDR
> + */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_drpause,
> + sizeof(sm_pause_drpause));
> + aspeed_jtag->status = JTAG_STATE_PAUSEDR;
> + break;
> + case JTAG_STATE_IDLE:
> + /* to Exit2 IR/DR->Updt IR/DR->IDLE */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_idle,
> + sizeof(sm_pause_idle));
> + aspeed_jtag->status = JTAG_STATE_IDLE;
> + break;
> + default:
> + break;
> + }
> + break;
> +
> + default:
> + dev_err(aspeed_jtag->dev, "aspeed_jtag_run_test_idle error\n");
> + break;
> + }
> +
> + /* Stay on IDLE for at least TCK cycle */
> + for (i = 0; i < runtest->tck; i++)
> + aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);
> +}
> +
> +/**
> + * aspeed_jtag_run_test_idle:
> + * JTAG reset: generates at least 9 TMS high and 1 TMS low to force
> + * devices into Run-Test/Idle State.
> + */
> +static int aspeed_jtag_idle(struct jtag *jtag,
> + struct jtag_run_test_idle *runtest)
> +{
> + struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
> +
> + dev_dbg(aspeed_jtag->dev, "aspeed_jtag runtest, status:%d, mode:%s, state:%s, reset:%d, tck:%d\n",
> + aspeed_jtag->status,
> + aspeed_jtag->mode & JTAG_XFER_HW_MODE ? "HW" : "SW",
> + end_status_str[runtest->endstate], runtest->reset,
> + runtest->tck);
> +
> + if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
> + aspeed_jtag_run_test_idle_sw(aspeed_jtag, runtest);
> + return 0;
> + }
> +
> + /* Disable sw mode */
> + aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
> + /* x TMS high + 1 TMS low */
> + if (runtest->reset)
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |
> + ASPEED_JTAG_CTL_ENG_OUT_EN |
> + ASPEED_JTAG_CTL_FORCE_TMS, ASPEED_JTAG_CTRL);
> + else
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_EC_GO_IDLE,
> + ASPEED_JTAG_EC);
> +
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
> + ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
> +
> + aspeed_jtag->status = JTAG_STATE_IDLE;
> + return 0;
> +}
> +
> +static void aspeed_jtag_xfer_sw(struct aspeed_jtag *aspeed_jtag,
> + struct jtag_xfer *xfer, unsigned long *data)
> +{
> + unsigned long remain_xfer = xfer->length;
> + unsigned long shift_bits = 0;
> + unsigned long index = 0;
> + unsigned long tdi;
> + char tdo;
> +
> + if (xfer->direction == JTAG_READ_XFER)
> + tdi = UINT_MAX;
> + else
> + tdi = data[index];
> +
> + while (remain_xfer > 1) {
> + tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0,
> + tdi & ASPEED_JTAG_DATA_MSB);
> + data[index] |= tdo << (shift_bits %
> + ASPEED_JTAG_DATA_CHUNK_SIZE);
> +
> + tdi >>= 1;
> + shift_bits++;
> + remain_xfer--;
> +
> + if (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE == 0) {
> + dev_dbg(aspeed_jtag->dev, "R/W data[%lu]:%lx\n",
> + index, data[index]);
> +
> + tdo = 0;
> + index++;
> +
> + if (xfer->direction == JTAG_READ_XFER)
> + tdi = UINT_MAX;
> + else
> + tdi = data[index];
> + }
> + }
> +
> + tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 1, tdi & ASPEED_JTAG_DATA_MSB);
> + data[index] |= tdo << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE);
> +}
> +
> +static void aspeed_jtag_xfer_push_data(struct aspeed_jtag *aspeed_jtag,
> + enum jtag_xfer_type type, u32 bits_len)
> +{
> + dev_dbg(aspeed_jtag->dev, "shift bits %d\n", bits_len);
> +
> + if (type == JTAG_SIR_XFER) {
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len),
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |
> + ASPEED_JTAG_CTL_INST_EN, ASPEED_JTAG_CTRL);
> + } else {
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len),
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |
> + ASPEED_JTAG_CTL_DATA_EN, ASPEED_JTAG_CTRL);
> + }
> +}
> +
> +static void aspeed_jtag_xfer_push_data_last(struct aspeed_jtag *aspeed_jtag,
> + enum jtag_xfer_type type,
> + u32 shift_bits,
> + enum jtag_endstate endstate)
> +{
> + if (endstate != JTAG_STATE_IDLE) {
> + if (type == JTAG_SIR_XFER) {
> + dev_dbg(aspeed_jtag->dev, "IR Keep Pause\n");
> +
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_IOUT_LEN(shift_bits),
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_IOUT_LEN(shift_bits) |
> + ASPEED_JTAG_CTL_INST_EN,
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_wait_instruction_pause(aspeed_jtag);
> + } else {
> + dev_dbg(aspeed_jtag->dev, "DR Keep Pause\n");
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_DOUT_LEN(shift_bits) |
> + ASPEED_JTAG_CTL_DR_UPDATE,
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_DOUT_LEN(shift_bits) |
> + ASPEED_JTAG_CTL_DR_UPDATE |
> + ASPEED_JTAG_CTL_DATA_EN,
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_wait_data_pause_complete(aspeed_jtag);
> + }
> + } else {
> + if (type == JTAG_SIR_XFER) {
> + dev_dbg(aspeed_jtag->dev, "IR go IDLE\n");
> +
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_IOUT_LEN(shift_bits) |
> + ASPEED_JTAG_CTL_LASPEED_INST,
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_IOUT_LEN(shift_bits) |
> + ASPEED_JTAG_CTL_LASPEED_INST |
> + ASPEED_JTAG_CTL_INST_EN,
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_wait_instruction_complete(aspeed_jtag);
> + } else {
> + dev_dbg(aspeed_jtag->dev, "DR go IDLE\n");
> +
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_DOUT_LEN(shift_bits) |
> + ASPEED_JTAG_CTL_LASPEED_DATA,
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_write(aspeed_jtag,
> + ASPEED_JTAG_DOUT_LEN(shift_bits) |
> + ASPEED_JTAG_CTL_LASPEED_DATA |
> + ASPEED_JTAG_CTL_DATA_EN,
> + ASPEED_JTAG_CTRL);
> + aspeed_jtag_wait_data_complete(aspeed_jtag);
> + }
> + }
> +}
> +
> +static void aspeed_jtag_xfer_hw(struct aspeed_jtag *aspeed_jtag,
> + struct jtag_xfer *xfer, unsigned long *data)
> +{
> + unsigned long remain_xfer = xfer->length;
> + unsigned long index = 0;
> + char shift_bits;
> + u32 data_reg;
> +
> + data_reg = xfer->type == JTAG_SIR_XFER ?
> + ASPEED_JTAG_INST : ASPEED_JTAG_DATA;
> + while (remain_xfer) {
> + if (xfer->direction == JTAG_WRITE_XFER) {
> + dev_dbg(aspeed_jtag->dev, "W dr->dr_data[%lu]:%lx\n",
> + index, data[index]);
> +
> + aspeed_jtag_write(aspeed_jtag, data[index], data_reg);
> + } else {
> + aspeed_jtag_write(aspeed_jtag, 0, data_reg);
> + }
> +
> + if (remain_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) {
> + shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE;
> +
> + /*
> + * Read bytes were not equals to column length
> + * and go to Pause-DR
> + */
> + aspeed_jtag_xfer_push_data(aspeed_jtag, xfer->type,
> + shift_bits);
> + } else {
> + /*
> + * Read bytes equals to column length =>
> + * Update-DR
> + */
> + shift_bits = remain_xfer;
> + aspeed_jtag_xfer_push_data_last(aspeed_jtag, xfer->type,
> + shift_bits,
> + xfer->endstate);
> + }
> +
> + if (xfer->direction == JTAG_READ_XFER) {
> + if (shift_bits < ASPEED_JTAG_DATA_CHUNK_SIZE) {
> + data[index] = aspeed_jtag_read(aspeed_jtag,
> + data_reg);
> +
> + data[index] >>= ASPEED_JTAG_DATA_CHUNK_SIZE -
> + shift_bits;
> + } else {
> + data[index] = aspeed_jtag_read(aspeed_jtag,
> + data_reg);
> + }
> + dev_dbg(aspeed_jtag->dev, "R dr->dr_data[%lu]:%lx\n",
> + index, data[index]);
> + }
> +
> + remain_xfer = remain_xfer - shift_bits;
> + index++;
> + dev_dbg(aspeed_jtag->dev, "remain_xfer %lu\n", remain_xfer);
> + }
> +}
> +
> +static int aspeed_jtag_xfer(struct jtag *jtag, struct jtag_xfer *xfer,
> + u8 *xfer_data)
> +{
> + static const u8 sm_update_shiftir[] = {1, 1, 0, 0};
> + static const u8 sm_update_shiftdr[] = {1, 0, 0};
> + static const u8 sm_pause_idle[] = {1, 1, 0};
> + static const u8 sm_pause_update[] = {1, 1};
> + struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
> + unsigned long *data = (unsigned long *)xfer_data;
> + unsigned long remain_xfer = xfer->length;
> + unsigned long offset;
> + char dbg_str[256];
> + int pos = 0;
> + int i;
> +
> + for (offset = 0, i = 0; offset < xfer->length;
> + offset += ASPEED_JTAG_DATA_CHUNK_SIZE, i++) {
> + pos += snprintf(&dbg_str[pos], sizeof(dbg_str) - pos,
> + "0x%08lx ", data[i]);
> + }
> +
> + dev_dbg(aspeed_jtag->dev, "aspeed_jtag %s %s xfer, mode:%s, END:%d, len:%lu, TDI[%s]\n",
> + xfer->type == JTAG_SIR_XFER ? "SIR" : "SDR",
> + xfer->direction == JTAG_READ_XFER ? "READ" : "WRITE",
> + aspeed_jtag->mode & JTAG_XFER_HW_MODE ? "HW" : "SW",
> + xfer->endstate, remain_xfer, dbg_str);
> +
> + if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
> + /* SW mode */
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
> + ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
> +
> + if (aspeed_jtag->status != JTAG_STATE_IDLE) {
> + /*IR/DR Pause->Exit2 IR / DR->Update IR /DR */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_update,
> + sizeof(sm_pause_update));
> + }
> +
> + if (xfer->type == JTAG_SIR_XFER)
> + /* ->IRSCan->CapIR->ShiftIR */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_update_shiftir,
> + sizeof(sm_update_shiftir));
> + else
> + /* ->DRScan->DRCap->DRShift */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_update_shiftdr,
> + sizeof(sm_update_shiftdr));
> +
> + aspeed_jtag_xfer_sw(aspeed_jtag, xfer, data);
> +
> + /* DIPause/DRPause */
> + aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);
> +
> + if (xfer->endstate == JTAG_STATE_IDLE) {
> + /* ->DRExit2->DRUpdate->IDLE */
> + aspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_idle,
> + sizeof(sm_pause_idle));
> + }
> + } else {
> + /* hw mode */
> + aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
> + aspeed_jtag_xfer_hw(aspeed_jtag, xfer, data);
> + }
> +
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
> + ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
> + aspeed_jtag->status = xfer->endstate;
> + return 0;
> +}
> +
> +static int aspeed_jtag_status_get(struct jtag *jtag, u32 *status)
> +{
> + struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
> +
> + *status = aspeed_jtag->status;
> + return 0;
> +}
> +
> +static irqreturn_t aspeed_jtag_interrupt(s32 this_irq, void *dev_id)
> +{
> + struct aspeed_jtag *aspeed_jtag = dev_id;
> + irqreturn_t ret;
> + u32 status;
> +
> + status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
> + dev_dbg(aspeed_jtag->dev, "status %x\n", status);
> +
> + if (status & ASPEED_JTAG_ISR_INT_MASK) {
> + aspeed_jtag_write(aspeed_jtag,
> + (status & ASPEED_JTAG_ISR_INT_MASK)
> + | (status & ASPEED_JTAG_ISR_INT_EN_MASK),
> + ASPEED_JTAG_ISR);
> + aspeed_jtag->flag |= status & ASPEED_JTAG_ISR_INT_MASK;
> + }
> +
> + if (aspeed_jtag->flag) {
> + wake_up_interruptible(&aspeed_jtag->jtag_wq);
> + ret = IRQ_HANDLED;
> + } else {
> + dev_err(aspeed_jtag->dev, "aspeed_jtag irq status:%x\n",
> + status);
> + ret = IRQ_NONE;
> + }
> + return ret;
> +}
> +
> +int aspeed_jtag_init(struct platform_device *pdev,
> + struct aspeed_jtag *aspeed_jtag)
> +{
> + struct resource *res;
> + int err;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + aspeed_jtag->reg_base = devm_ioremap_resource(aspeed_jtag->dev, res);
> + if (IS_ERR(aspeed_jtag->reg_base))
> + return -ENOMEM;
> +
> + aspeed_jtag->pclk = devm_clk_get(aspeed_jtag->dev, NULL);
> + if (IS_ERR(aspeed_jtag->pclk)) {
> + dev_err(aspeed_jtag->dev, "devm_clk_get failed\n");
> + return PTR_ERR(aspeed_jtag->pclk);
> + }
> +
> + clk_prepare_enable(aspeed_jtag->pclk);
> +
> + aspeed_jtag->irq = platform_get_irq(pdev, 0);
> + if (aspeed_jtag->irq < 0) {
> + dev_err(aspeed_jtag->dev, "no irq specified\n");
> + err = -ENOENT;
> + goto clk_unprep;
> + }
> +
> + /* Enable clock */
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |
> + ASPEED_JTAG_CTL_ENG_OUT_EN, ASPEED_JTAG_CTRL);
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
> + ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);
> +
> + err = devm_request_irq(aspeed_jtag->dev, aspeed_jtag->irq,
> + aspeed_jtag_interrupt, 0,
> + "aspeed-jtag", aspeed_jtag);
> + if (err) {
> + dev_err(aspeed_jtag->dev, "aspeed_jtag unable to get IRQ");
> + goto clk_unprep;
> + }
> + dev_dbg(&pdev->dev, "aspeed_jtag:IRQ %d.\n", aspeed_jtag->irq);
> +
> + aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_PAUSE |
> + ASPEED_JTAG_ISR_INST_COMPLETE |
> + ASPEED_JTAG_ISR_DATA_PAUSE |
> + ASPEED_JTAG_ISR_DATA_COMPLETE |
> + ASPEED_JTAG_ISR_INST_PAUSE_EN |
> + ASPEED_JTAG_ISR_INST_COMPLETE_EN |
> + ASPEED_JTAG_ISR_DATA_PAUSE_EN |
> + ASPEED_JTAG_ISR_DATA_COMPLETE_EN,
> + ASPEED_JTAG_ISR);
> +
> + aspeed_jtag->flag = 0;
> + aspeed_jtag->mode = 0;
> + init_waitqueue_head(&aspeed_jtag->jtag_wq);
> + return 0;
> +
> +clk_unprep:
> + clk_disable_unprepare(aspeed_jtag->pclk);
> + return err;
> +}
> +
> +int aspeed_jtag_deinit(struct platform_device *pdev,
> + struct aspeed_jtag *aspeed_jtag)
> +{
> + aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_ISR);
> + /* Disable clock */
> + aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL);
> + clk_disable_unprepare(aspeed_jtag->pclk);
> + return 0;
> +}
> +
> +static const struct jtag_ops aspeed_jtag_ops = {
> + .freq_get = aspeed_jtag_freq_get,
> + .freq_set = aspeed_jtag_freq_set,
> + .status_get = aspeed_jtag_status_get,
> + .idle = aspeed_jtag_idle,
> + .xfer = aspeed_jtag_xfer,
> + .mode_set = aspeed_jtag_mode_set
> +};
> +
> +static int aspeed_jtag_probe(struct platform_device *pdev)
> +{
> + struct aspeed_jtag *aspeed_jtag;
> + struct jtag *jtag;
> + int err;
> +
> + if (!of_device_is_compatible(pdev->dev.of_node, "aspeed,aspeed-jtag"))
Should this be "aspeed,ast2400-jtag"/"aspeed,ast2500-jtag" as
specified in the compatible string below?
> + return -ENOMEM;
> +
> + jtag = jtag_alloc(sizeof(*aspeed_jtag), &aspeed_jtag_ops);
> + if (!jtag)
> + return -ENODEV;
> +
> + platform_set_drvdata(pdev, jtag);
> + aspeed_jtag = jtag_priv(jtag);
> + aspeed_jtag->dev = &pdev->dev;
> +
> + /* Initialize device*/
> + err = aspeed_jtag_init(pdev, aspeed_jtag);
> + if (err)
> + goto err_jtag_init;
> +
> + /* Initialize JTAG core structure*/
> + err = jtag_register(jtag);
> + if (err)
> + goto err_jtag_register;
> +
> + return 0;
> +
> +err_jtag_register:
> + aspeed_jtag_deinit(pdev, aspeed_jtag);
> +err_jtag_init:
> + jtag_free(jtag);
> + return err;
> +}
> +
> +static int aspeed_jtag_remove(struct platform_device *pdev)
> +{
> + struct jtag *jtag;
> +
> + jtag = platform_get_drvdata(pdev);
> + aspeed_jtag_deinit(pdev, jtag_priv(jtag));
> + jtag_unregister(jtag);
> + jtag_free(jtag);
> + return 0;
> +}
> +
> +static const struct of_device_id aspeed_jtag_of_match[] = {
> + { .compatible = "aspeed,ast2400-jtag", },
> + { .compatible = "aspeed,ast2500-jtag", },
> + {}
> +};
> +
> +static struct platform_driver aspeed_jtag_driver = {
> + .probe = aspeed_jtag_probe,
> + .remove = aspeed_jtag_remove,
> + .driver = {
> + .name = ASPEED_JTAG_NAME,
> + .of_match_table = aspeed_jtag_of_match,
> + },
> +};
> +module_platform_driver(aspeed_jtag_driver);
> +
> +MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
> +MODULE_DESCRIPTION("ASPEED JTAG driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.1
>
--
Regards,
Kun
^ permalink raw reply
* Re: [RFC 0/2] of: Add whitelist
From: Frank Rowand @ 2017-11-29 22:47 UTC (permalink / raw)
To: Alan Tull, Rob Herring, Pantelis Antoniou
Cc: Moritz Fischer, devicetree, linux-kernel, linux-fpga
In-Reply-To: <da4c9b29-eccc-6a67-291a-73a36c1598b5@gmail.com>
On 11/29/17 04:20, Frank Rowand wrote:
> On 11/27/17 15:58, Alan Tull wrote:
>> Here's a proposal for a whitelist to lock down the dynamic device tree.
>>
>> For an overlay to be accepted, all of its targets are required to be
>> on a target node whitelist.
>>
>> Currently the only way I have to get on the whitelist is calling a
>> function to add a node. That works for fpga regions, but I think
>> other uses will need a way of having adding specific nodes from the
>> base device tree, such as by adding a property like 'allow-overlay;'
>> or 'allow-overlay = "okay";' If that is acceptable, I could use some
>> advice on where that particular code should go.
>>
>> Alan
>>
>> Alan Tull (2):
>> of: overlay: add whitelist
>> fpga: of region: add of-fpga-region to whitelist
>>
>> drivers/fpga/of-fpga-region.c | 9 ++++++
>> drivers/of/overlay.c | 73 +++++++++++++++++++++++++++++++++++++++++++
>> include/linux/of.h | 12 +++++++
>> 3 files changed, 94 insertions(+)
>>
>
> The plan was to use connectors to restrict where an overlay could be applied.
> I would prefer not to have multiple methods for accomplishing the same thing
> unless there is a compelling reason to do so.
Going back one level in my thinking, I don't think that having a driver mark
a node as a location where an overlay fragment can be applied is serving a
useful purpose. Any driver, including any driver loaded as a module,
could mark a node as ok. I don't see how this is providing any meaningful
restriction on where an overlay fragment can be applied.
-Frank
^ permalink raw reply
* Re: [PATCH v4 7/8] netdev: octeon-ethernet: Add Cavium Octeon III support.
From: Andrew Lunn @ 2017-11-29 22:16 UTC (permalink / raw)
To: Dan Carpenter
Cc: Mark Rutland, linux-mips, devel, devicetree, netdev, David Daney,
linux-kernel, ralf, Carlos Munoz, Rob Herring, Souptick Joarder,
Steven J. Hill, Greg Kroah-Hartman, Florian Fainelli, James Hogan,
David S. Miller
In-Reply-To: <20171129191138.ntlfw5fb4xacwyun@mwanda>
On Wed, Nov 29, 2017 at 10:11:38PM +0300, Dan Carpenter wrote:
> On Wed, Nov 29, 2017 at 09:37:15PM +0530, Souptick Joarder wrote:
> > >> +static int bgx_port_sgmii_set_link_speed(struct bgx_port_priv *priv, struct port_status status)
> > >> +{
> > >> + u64 data;
> > >> + u64 prtx;
> > >> + u64 miscx;
> > >> + int timeout;
> > >> +
> >
> > >> +
> > >> + switch (status.speed) {
> > >> + case 10:
> > >
> > > In my opinion, instead of hard coding the value, is it fine to use ENUM ?
> > Similar comments applicable in other places where hard coded values are used.
> >
>
> 10 means 10M right? That's not really a magic number. It's fine.
There are also :
uapi/linux/ethtool.h:#define SPEED_10 10
uapi/linux/ethtool.h:#define SPEED_100 100
uapi/linux/ethtool.h:#define SPEED_1000 1000
uapi/linux/ethtool.h:#define SPEED_10000 10000
uapi/linux/ethtool.h:#define SPEED_100000 100000
Andrew
^ permalink raw reply
* Re: [PATCH] rtc: add mxc driver for i.MX53
From: Alexandre Belloni @ 2017-11-29 22:11 UTC (permalink / raw)
To: linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w
Cc: Alessandro Zummo, Patrick Bruenn, Rob Herring, Mark Rutland,
open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
Shawn Guo, Sascha Hauer, Russell King,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20171128073927.12035-1-linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
Hi,
A really quick review:
On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org wrote:
> From: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
>
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
>
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
>
I'd say this doesn't add much information as this link is probably bound
to die at some point (especially seeing the NXP/Qualcomm/Broadcom
story).
> Signed-off-by: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
>
> ---
>
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?
This seems different enough to be a separate driver.
> - document DT binding "fsl,imx53-rtc" accordingly
Yes, this has to be documented in a previous patch
> - Should unused defines be removed or kept for someone else to be
> useful?
I don't care much, either are fine but the less lines, the easier the
reviews.
> - Is the use of __raw_readl/writel() correct? Should it be replaced with
> readl/writel()?
The __raw version will not work if someone is running a BE kernel so
they should be moved to the _relaxed version or the usual readl/writel.
> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
> the pattern from rtc-mxc.c?
If you mean using SIMPLE_DEV_PM_OPS, yes, you should do that.
> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
> the imx53.dtsi change into a separate patch based on his tree? Or can
> we still stop the full revert and just remove the imx25-rtc compatible?
> I am not in a hurry, so we could just wait until the revert landed in
> Linus tree. Whatever you think is best.
>
I'm not taking DT changes through the RTC tree so it should be in a
separate patch that will go through Shawn's tree
You should also use checkpatch --strict, most of the warnings are
correct.
> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
>
> To: Alessandro Zummo <a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>
> To: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list)
> Cc: Fabio Estevam <fabio.estevam-3arQi8VN3Tc@public.gmane.org>
> Cc: Juergen Borleis <jbe-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Cc: Noel Vellemans <Noel.Vellemans-8UENEgx6w+makBO8gow8eQ@public.gmane.org>
> Cc: Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Sascha Hauer <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> (maintainer:ARM PORT)
> Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
> arch/arm/boot/dts/imx53.dtsi | 2 +-
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-mxc_v2.c | 531 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 533 insertions(+), 1 deletion(-)
> create mode 100644 drivers/rtc/rtc-mxc_v2.c
>
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
> };
>
> srtc: srtc@53fa4000 {
> - compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> + compatible = "fsl,imx53-rtc";
> reg = <0x53fa4000 0x4000>;
> interrupts = <24>;
> interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
> obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
> obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
> obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc_v2.o
This definitively needs a different Kconfig symbol.
> obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
> obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
> obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@
I think SPDX identifier will soon be required on new files, please add
one.
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +
Is that comment really useful?
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>
This should be in alphabetical order
> +//#include <linux/mxc_srtc.h>
This is not useful
> +#define RTC_READ_TIME_47BIT _IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET _IOR('p', 0x21, int64_t)
> +
Those ioctls are not used.
> +#define SRTC_LPSCLR_LLPSC_LSH 17 /* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT 0x41736166 /* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP (1 << 0) /* lp software reset */
> +#define SRTC_LPCR_EN_LP (1 << 3) /* lp enable */
> +#define SRTC_LPCR_WAE (1 << 4) /* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE (1 << 5) /* lp security alarm enable */
> +#define SRTC_LPCR_SI (1 << 6) /* lp security interrupt enable */
> +#define SRTC_LPCR_ALP (1 << 7) /* lp alarm flag */
> +#define SRTC_LPCR_LTC (1 << 8) /* lp lock time counter */
> +#define SRTC_LPCR_LMC (1 << 9) /* lp lock monotonic counter */
> +#define SRTC_LPCR_SV (1 << 10) /* lp security violation */
> +#define SRTC_LPCR_NSA (1 << 11) /* lp non secure access */
> +#define SRTC_LPCR_NVEIE (1 << 12) /* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE (1 << 13) /* lp init state exit int enable */
> +#define SRTC_LPCR_NVE (1 << 14) /* lp non valid state exit bit */
> +#define SRTC_LPCR_IE (1 << 15) /* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> + SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> + SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI (1 << 0) /* lp time read invalidate */
> +#define SRTC_LPSR_PGD (1 << 1) /* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD (1 << 2) /* lp clock tampering detected */
> +#define SRTC_LPSR_ALP (1 << 3) /* lp alarm flag */
> +#define SRTC_LPSR_MR (1 << 4) /* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR (1 << 5) /* lp time rollover */
> +#define SRTC_LPSR_EAD (1 << 6) /* lp external alarm detected */
> +#define SRTC_LPSR_IT0 (1 << 7) /* lp IIM throttle */
> +#define SRTC_LPSR_IT1 (1 << 8)
> +#define SRTC_LPSR_IT2 (1 << 9)
> +#define SRTC_LPSR_SM0 (1 << 10) /* lp security mode */
> +#define SRTC_LPSR_SM1 (1 << 11)
> +#define SRTC_LPSR_STATE_LP0 (1 << 12) /* lp state */
> +#define SRTC_LPSR_STATE_LP1 (1 << 13)
> +#define SRTC_LPSR_NVES (1 << 14) /* lp non-valid state exit status */
> +#define SRTC_LPSR_IES (1 << 15) /* lp init state exit status */
> +
> +#define MAX_PIE_NUM 15
> +#define MAX_PIE_FREQ 32768
> +#define MIN_PIE_FREQ 1
> +
> +#define SRTC_PI0 (1 << 0)
> +#define SRTC_PI1 (1 << 1)
> +#define SRTC_PI2 (1 << 2)
> +#define SRTC_PI3 (1 << 3)
> +#define SRTC_PI4 (1 << 4)
> +#define SRTC_PI5 (1 << 5)
> +#define SRTC_PI6 (1 << 6)
> +#define SRTC_PI7 (1 << 7)
> +#define SRTC_PI8 (1 << 8)
> +#define SRTC_PI9 (1 << 9)
> +#define SRTC_PI10 (1 << 10)
> +#define SRTC_PI11 (1 << 11)
> +#define SRTC_PI12 (1 << 12)
> +#define SRTC_PI13 (1 << 13)
> +#define SRTC_PI14 (1 << 14)
> +#define SRTC_PI15 (1 << 15)
> +
> +#define PIT_ALL_ON (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> + SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> + SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> + SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP (1 << 0) /* hp software reset */
> +#define SRTC_EN_HP (1 << 3) /* hp enable */
> +#define SRTC_TS (1 << 4) /* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP (1 << 16) /* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP (1 << 18) /* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP (1 << 19) /* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP (1 << 16) /* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP (1 << 18) /* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP (1 << 19) /* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP (1 << 20) /* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP (1 << 21) /* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR 0x00 /* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR 0x04 /* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR 0x08 /* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR 0x0C /* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR 0x10 /* LP Control Reg */
> +#define SRTC_LPSR 0x14 /* LP Status Reg */
> +#define SRTC_LPPDR 0x18 /* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR 0x1C /* LP General Purpose Reg */
> +#define SRTC_HPCMR 0x20 /* HP Counter MSB Reg */
> +#define SRTC_HPCLR 0x24 /* HP Counter LSB Reg */
> +#define SRTC_HPAMR 0x28 /* HP Alarm MSB Reg */
> +#define SRTC_HPALR 0x2C /* HP Alarm LSB Reg */
> +#define SRTC_HPCR 0x30 /* HP Control Reg */
> +#define SRTC_HPISR 0x34 /* HP Interrupt Status Reg */
> +#define SRTC_HPIENR 0x38 /* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK 0x3 /* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW 0x0 /* Low Security */
> +#define SRTC_SECMODE_MED 0x1 /* Medium Security */
> +#define SRTC_SECMODE_HIGH 0x2 /* High Security */
> +#define SRTC_SECMODE_RESERVED 0x3 /* Reserved */
> +
> +struct rtc_drv_data {
> + struct rtc_device *rtc;
> + void __iomem *ioaddr;
> + int irq;
> + struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);
> +
Shouldn't that lock be part of rtc_drv_data?
> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */
> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> + unsigned int i, count;
> + /* Wait for 3 CKIL cycles */
> + for (i = 0; i < 3; i++) {
> + count = readl(ioaddr + SRTC_LPSCLR);
> + while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> + ;
> + }
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param alrm the new alarm value to be updated in the RTC
> + *
> + * @return 0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{
> + struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> + void __iomem *ioaddr = pdata->ioaddr;
> + struct rtc_time alarm_tm, now_tm;
> + unsigned long now, time;
> + int ret;
> +
> + now = __raw_readl(ioaddr + SRTC_LPSCMR);
> + rtc_time_to_tm(now, &now_tm);
> +
> + alarm_tm.tm_year = now_tm.tm_year;
> + alarm_tm.tm_mon = now_tm.tm_mon;
> + alarm_tm.tm_mday = now_tm.tm_mday;
> +
> + alarm_tm.tm_hour = alrm->tm_hour;
> + alarm_tm.tm_min = alrm->tm_min;
> + alarm_tm.tm_sec = alrm->tm_sec;
> +
> + rtc_tm_to_time(&now_tm, &now);
> + rtc_tm_to_time(&alarm_tm, &time);
> +
> + if (time < now) {
> + time += 60 * 60 * 24;
> + rtc_time_to_tm(time, &alarm_tm);
> + }
> + ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> + __raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> + /* clear alarm interrupt status bit */
> + __raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> + return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param irq RTC IRQ number
> + * @param dev_id device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> + struct platform_device *pdev = dev_id;
> + struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> + void __iomem *ioaddr = pdata->ioaddr;
> + u32 lp_status, lp_cr;
> + u32 events = 0;
> +
> + lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> + lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> + /* update irq data & counter */
> + if (lp_status & SRTC_LPSR_ALP) {
> + if (lp_cr & SRTC_LPCR_ALP)
> + events |= (RTC_AF | RTC_IRQF);
> +
> + /* disable further lp alarm interrupts */
> + lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> + }
> +
> + /* Update interrupt enables */
> + __raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> + /* clear interrupt status */
> + __raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> + rtc_write_sync_lp(ioaddr);
> + rtc_update_irq(pdata->rtc, 1, events);
> + return IRQ_HANDLED;
> +}
> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param tm contains the RTC time value upon return
> + *
> + * @return 0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> + time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> + rtc_time_to_tm(now, tm);
> + return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param tm the time value to be set in the RTC
> + *
> + * @return 0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> + time64_t time = rtc_tm_to_time64(tm);
> +
> + if (time > UINT_MAX) {
> + dev_warn(dev, "time_t has overflow\n");
> + }
> +
> + writel(time, pdata->ioaddr + SRTC_LPSCMR);
> + rtc_write_sync_lp(pdata->ioaddr);
> + return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param alrm contains the RTC alarm value upon return
> + *
> + * @return 0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> + void __iomem *ioaddr = pdata->ioaddr;
> +
> + rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> + alrm->pending =
> + ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
> +
> + return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> + struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> + unsigned long lock_flags = 0;
> + u32 lp_cr;
> +
> + spin_lock_irqsave(&rtc_lock, lock_flags);
> + lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> + if (enable)
> + lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> + else
> + lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> + __raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> + spin_unlock_irqrestore(&rtc_lock, lock_flags);
> + return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param alrm the alarm value to be set in the RTC
> + *
> + * @return 0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> + void __iomem *ioaddr = pdata->ioaddr;
> + int ret;
> +
> + ret = rtc_update_alarm(dev, &alrm->time);
> + if (!ret)
> + mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> + rtc_write_sync_lp(ioaddr);
> + return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> + .read_time = mxc_rtc_read_time,
> + .set_time = mxc_rtc_set_time,
> + .read_alarm = mxc_rtc_read_alarm,
> + .set_alarm = mxc_rtc_set_alarm,
> + .alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */
This comment is probably wrong ;)
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> + struct timespec tv;
> + struct resource *res;
> + struct rtc_drv_data *pdata = NULL;
> + void __iomem *ioaddr;
> + int ret = 0;
> +
> + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> + if (!pdata)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res)
> + return -ENODEV;
> +
> + pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(pdata->ioaddr))
> + return PTR_ERR(pdata->ioaddr);
> +
> + ioaddr = pdata->ioaddr;
> +
> + pdata->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(pdata->clk)) {
> + dev_err(&pdev->dev, "unable to get rtc clock!\n");
> + return PTR_ERR(pdata->clk);
> + }
> + ret = clk_prepare_enable(pdata->clk);
> + if (ret)
> + return ret;
> +
> + /* Configure and enable the RTC */
> + pdata->irq = platform_get_irq(pdev, 0);
> + if (pdata->irq >= 0
> + && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> + IRQF_SHARED, pdev->name, pdev) < 0) {
> + dev_warn(&pdev->dev, "interrupt not available.\n");
> + pdata->irq = -1;
> + }
> +
> + if (pdata->irq >= 0)
> + device_init_wakeup(&pdev->dev, 1);
> +
> + /* initialize glitch detect */
> + __raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> + udelay(100);
> +
> + /* clear lp interrupt status */
> + __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> + udelay(100);
> +
> + /* move out of init state */
> + __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> + udelay(100);
> +
> + while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> + ;
> +
> + /* move out of non-valid state */
> + __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> + SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> + udelay(100);
> +
> + while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> + ;
> +
> + __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> + udelay(100);
> +
> + platform_set_drvdata(pdev, pdata);
> + pdata->rtc =
> + devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> + THIS_MODULE);
> + if (IS_ERR(pdata->rtc)) {
> + ret = PTR_ERR(pdata->rtc);
> + goto exit_put_clk;
> + }
> +
> + tv.tv_nsec = 0;
> + tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> + /* By default, devices should wakeup if they can */
> + /* So srtc is set as "should wakeup" as it can */
That comment is not formatted correctly.
> + device_init_wakeup(&pdev->dev, 1);
> +
> + return ret;
For clarity, this has to return 0.
> +
> +exit_put_clk:
> + clk_disable_unprepare(pdata->clk);
> + return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> + struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> + clk_disable_unprepare(pdata->clk);
> + return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param pdev not used
> + * @param state Power state to enter.
> + *
> + * @return The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> + struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> + if (device_may_wakeup(&pdev->dev))
> + enable_irq_wake(pdata->irq);
> +
> + return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param pdev not used
> + *
> + * @return The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> + struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> + if (device_may_wakeup(&pdev->dev))
> + disable_irq_wake(pdata->irq);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> + {.compatible = "fsl,imx53-rtc",},
> + {}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.
> + */
> +static struct platform_driver mxc_rtc_driver = {
> + .driver = {
> + .name = "mxc_rtc_v8",
Isn't it weird to have v8 here when the file is named v2?
> + .of_match_table = mxc_ids,
> + },
> + .probe = mxc_rtc_probe,
> + .remove = mxc_rtc_remove,
> + .suspend = mxc_rtc_suspend,
> + .resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");
> --
> 2.11.0
>
>
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 2/2] dt-bindings: iio: temperature: add MLX90632 device bindings
From: Crt Mori @ 2017-11-29 22:08 UTC (permalink / raw)
To: Jonathan Cameron
Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Crt Mori
Add device tree bindings for MLX90632 IR temperature sensor.
Signed-off-by: Crt Mori <cmo-fc6wVz46lShBDgjK7y7TUQ@public.gmane.org>
---
.../bindings/iio/temperature/mlx90632.txt | 28 ++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
new file mode 100644
index 000000000000..6073a5ccf9a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
@@ -0,0 +1,28 @@
+* Melexis MLX90632 contactless Infra Red temperature sensor
+
+Link to datasheet: https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90632
+
+There are various applications for the Infra Red contactless temperature sensor
+and MLX90632 is most suitable for consumer applications where measured object
+temperature is in range between -20 to 200 degrees Celsius with relative error
+of measurement below 1 degree Celsius in object temperature range for
+industrial applications. Since it can operate and measure ambient temperature
+in range of -20 to 85 degrees Celsius it is suitable also for outdoor use.
+
+Be aware that electronics surrounding the sensor can increase ambient
+temperature. MLX90632 can be calibrated to reduce the housing effect via
+already existing EEPROM parameters.
+
+Since measured object emissivity effects Infra Red energy emitted, emissivity
+should be set before requesting the object temperature.
+
+Required properties:
+ - compatible: should be "melexis,mlx90632"
+ - reg: the I2C address of the sensor (default 0x3a)
+
+Example:
+
+mlx90632@02 {
+ compatible = "melexis,mlx90632";
+ reg = <0x3a>;
+};
--
2.15.0
^ permalink raw reply related
* Re: [PATCH 3/4] RFC: net: dsa: Add bindings for Realtek SMI DSAs
From: Andrew Lunn @ 2017-11-29 21:56 UTC (permalink / raw)
To: Linus Walleij
Cc: Vivien Didelot, Florian Fainelli, netdev, Antti Seppälä,
Roman Yeryomin, Colin Leitner, Gabor Juhos,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
In-Reply-To: <CACRpkdZVXgFMiHpyUqw7ONYDcq6Htn3rTMRaBJkzd6T3WtX36A@mail.gmail.com>
Hi Linus
> Just that the PHYs are on the MDIO bus inside the switch, of
> course.
I think the problem might be, you are using the DSA provided MDIO bus.
The Marvell switches has a similar setup in terms of interrupts. The
PHY interrupts appear within the switch. So i implemented an interrupt
controller, just the same as you.
The problem is, the DSA provided MDIO bus is not linked to device
tree. So you cannot have phy nodes in device tree associated to it.
What i did for the Marvell driver is that driver itself implements an
MDIO bus (two actually in some chips), and the internal or external
PHYs are placed on the switch drivers MDIO bus, rather than the DSA
MDIO bus. The switch driver MDIO bus links to an mdio node in device
tree. I can then have interrupt properties in the phys on this MDIO
bus in device tree.
What actually might make sense, is to have the DSA MDIO bus look
inside the switches device tree node and see if there is an mdio
node. If so allow dsa_switch_setup() to use of_mdiobus_register()
instead of mdiobus_register().
Andrew
^ permalink raw reply
* Re: [PATCH 3/4] RFC: net: dsa: Add bindings for Realtek SMI DSAs
From: Florian Fainelli @ 2017-11-29 21:48 UTC (permalink / raw)
To: Linus Walleij, Andrew Lunn
Cc: Vivien Didelot, netdev-u79uwXL29TY76Z2rM5mHXA,
Antti Seppälä, Roman Yeryomin, Colin Leitner,
Gabor Juhos,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
In-Reply-To: <CACRpkdZVXgFMiHpyUqw7ONYDcq6Htn3rTMRaBJkzd6T3WtX36A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 11/29/2017 01:28 PM, Linus Walleij wrote:
> On Wed, Nov 29, 2017 at 4:56 PM, Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org> wrote:
>>> I have the phy-handle in the ethernet controller. This RTL8366RB
>>> thing is just one big PHY as far as I know.
>>
>> We don't model switches as PHYs. They are their own device type. And
>> the internal or external PHYs are just normal PHYs in the linux
>> model. Meaning their interrupt properties goes in the PHY node in
>> device tree, as documented in the phy.txt binding documentation.
>
> I do model the PHYs on the switch as PHYs.
> They are using the driver in drivers/phy/realtek.c.
That's good.
>
> The interrupts are assigned to the PHYs not to the Switch.
> Just that the PHYs are on the MDIO bus inside the switch, of
> course.
>
> The switch however provides an irqchip to demux the interrupts.
>
> I think there is some misunderstanding in what I'm trying to do..
>
> I have tried learning the DSA ideas by reading e.g. your paper:
> https://www.netdevconf.org/2.1/papers/distributed-switch-architecture.pdf
>
> So I try my best to conform with these ideas.
>
> I however have a hard time testing things since I don't really have a
> system to compare to. What would be useful is to know how
> commands like "ip" and "ifconfig" are used on a typical
> say home router.
There is a mock-up driver: drivers/net/dsa/dsa_loop.c which does not
pass any packets, but at least allows you to exercise user-space tools
and so on.
--
Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 19/19] ASoC: tlv320aic31xx: Add button press detection
From: Andrew F. Davis @ 2017-11-29 21:33 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel, devicetree, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
This device can optionally detect headset or microphone button presses.
Add support for this by passing this event to the jack layer.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 14 +++++++++++++-
sound/soc/codecs/tlv320aic31xx.h | 3 ++-
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 471b31be55d1..8cd27c99cb15 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1280,9 +1280,20 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
if (value & AIC31XX_HPRSCDETECT)
dev_err(dev, "Short circuit on Right output is detected\n");
- if (value & AIC31XX_HSPLUG) {
+ if (value & (AIC31XX_HSPLUG | AIC31XX_BUTTONPRESS)) {
int status = 0;
+ ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG2,
+ &value);
+ if (ret) {
+ dev_err(dev, "Failed to read interrupt mask: %d\n",
+ ret);
+ return IRQ_NONE;
+ }
+
+ if (value & AIC31XX_BUTTONPRESS)
+ status |= SND_JACK_BTN_0;
+
ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &value);
if (ret) {
dev_err(dev, "Failed to read headset type: %d\n", ret);
@@ -1395,6 +1406,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
AIC31XX_HSPLUGDET |
+ AIC31XX_BUTTONPRESSDET |
AIC31XX_SC |
AIC31XX_ENGINE);
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 66c85df4d5be..7fce278eadac 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -21,7 +21,8 @@
#define DAC31XX_BIT BIT(3)
#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \
- SND_JACK_HEADSET)
+ SND_JACK_HEADSET | \
+ SND_JACK_BTN_0)
enum aic31xx_type {
AIC3100 = 0,
--
2.15.0
^ permalink raw reply related
* [PATCH v2 18/19] ASoC: tlv320aic31xx: Add headphone/headset detection
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd-l0cyMroinI0@public.gmane.org>
This device can detect the insertion/removal of headphones and headsets.
Enable reporting this status by enabling this interrupt and forwarding
this to upper-layers if a jack has been defined.
This jack definition and the resulting operation from a jack detection
event must currently be defined by sound card platform code until CODEC
outputs to jack mappings can be defined generically.
Signed-off-by: Andrew F. Davis <afd-l0cyMroinI0@public.gmane.org>
---
sound/soc/codecs/tlv320aic31xx.c | 33 +++++++++++++++++++++++++++++++++
sound/soc/codecs/tlv320aic31xx.h | 11 +++++++++++
2 files changed, 44 insertions(+)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 094b1596f9cc..471b31be55d1 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -25,6 +25,7 @@
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -89,6 +90,7 @@ static bool aic31xx_volatile(struct device *dev, unsigned int reg)
case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
case AIC31XX_INTRDACFLAG2:
case AIC31XX_INTRADCFLAG2:
+ case AIC31XX_HSDETECT:
return true;
}
return false;
@@ -161,6 +163,7 @@ struct aic31xx_priv {
struct gpio_desc *gpio_reset;
int micbias_vg;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
+ struct snd_soc_jack *jack;
unsigned int sysclk;
u8 p_div;
int rate_div_line;
@@ -1277,6 +1280,32 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
if (value & AIC31XX_HPRSCDETECT)
dev_err(dev, "Short circuit on Right output is detected\n");
+ if (value & AIC31XX_HSPLUG) {
+ int status = 0;
+
+ ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &value);
+ if (ret) {
+ dev_err(dev, "Failed to read headset type: %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ switch ((value & AIC31XX_HSD_TYPE_MASK) >>
+ AIC31XX_HSD_TYPE_SHIFT) {
+ case AIC31XX_HSD_HP:
+ status |= SND_JACK_HEADPHONE;
+ break;
+ case AIC31XX_HSD_HS:
+ status |= SND_JACK_HEADSET;
+ break;
+ default:
+ break;
+ }
+
+ if (aic31xx->jack)
+ snd_soc_jack_report(aic31xx->jack, status,
+ AIC31XX_JACK_MASK);
+ }
+
ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value);
if (ret) {
dev_err(dev, "Failed to read overflow flag: %d\n", ret);
@@ -1365,9 +1394,13 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
+ AIC31XX_HSPLUGDET |
AIC31XX_SC |
AIC31XX_ENGINE);
+ regmap_write(aic31xx->regmap, AIC31XX_HSDETECT,
+ AIC31XX_HSD_ENABLE);
+
ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq,
NULL, aic31xx_irq,
IRQF_ONESHOT, "aic31xx-irq",
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index d062663f66b5..66c85df4d5be 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -20,6 +20,9 @@
#define AIC31XX_MINIDSP_BIT BIT(2)
#define DAC31XX_BIT BIT(3)
+#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \
+ SND_JACK_HEADSET)
+
enum aic31xx_type {
AIC3100 = 0,
AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
@@ -213,6 +216,14 @@ enum aic31xx_type {
/* AIC31XX_DACMUTE */
#define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
+/* AIC31XX_HSDETECT */
+#define AIC31XX_HSD_ENABLE BIT(7)
+#define AIC31XX_HSD_TYPE_MASK GENMASK(6, 5)
+#define AIC31XX_HSD_TYPE_SHIFT 5
+#define AIC31XX_HSD_NONE 0x00
+#define AIC31XX_HSD_HP 0x01
+#define AIC31XX_HSD_HS 0x03
+
/* AIC31XX_MICBIAS */
#define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
#define AIC31XX_MICBIAS_SHIFT 0
--
2.15.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 17/19] ASoC: tlv320aic31xx: Add overflow detection support
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel, devicetree, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
Similar to short circuit detection, when the ADC/DAC is saturated and
overflows poor audio quality can result and should be reported to the
user. This device support Automatic Dynamic Range Compression (DRC)
to reduce this but it is not enabled currently in this driver.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 20 +++++++++++++++++++-
sound/soc/codecs/tlv320aic31xx.h | 7 +++++++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index fd3109366377..094b1596f9cc 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1277,6 +1277,23 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
if (value & AIC31XX_HPRSCDETECT)
dev_err(dev, "Short circuit on Right output is detected\n");
+ ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value);
+ if (ret) {
+ dev_err(dev, "Failed to read overflow flag: %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (value & AIC31XX_DAC_OF_LEFT)
+ dev_err(dev, "Left-channel DAC overflow has occurred\n");
+ if (value & AIC31XX_DAC_OF_RIGHT)
+ dev_err(dev, "Right-channel DAC overflow has occurred\n");
+ if (value & AIC31XX_DAC_OF_SHIFTER)
+ dev_err(dev, "DAC barrel shifter overflow has occurred\n");
+ if (value & AIC31XX_ADC_OF)
+ dev_err(dev, "ADC overflow has occurred\n");
+ if (value & AIC31XX_ADC_OF_SHIFTER)
+ dev_err(dev, "ADC barrel shifter overflow has occurred\n");
+
return IRQ_HANDLED;
}
@@ -1348,7 +1365,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
- AIC31XX_SC);
+ AIC31XX_SC |
+ AIC31XX_ENGINE);
ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq,
NULL, aic31xx_irq,
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 9dc85b6f6ad3..d062663f66b5 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -166,6 +166,13 @@ enum aic31xx_type {
#define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1)
#define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
+/* AIC31XX_OFFLAG */
+#define AIC31XX_DAC_OF_LEFT BIT(7)
+#define AIC31XX_DAC_OF_RIGHT BIT(6)
+#define AIC31XX_DAC_OF_SHIFTER BIT(5)
+#define AIC31XX_ADC_OF BIT(3)
+#define AIC31XX_ADC_OF_SHIFTER BIT(1)
+
/* AIC31XX_INTRDACFLAG */
#define AIC31XX_HPLSCDETECT BIT(7)
#define AIC31XX_HPRSCDETECT BIT(6)
--
2.15.0
^ permalink raw reply related
* [PATCH v2 16/19] ASoC: tlv320aic31xx: Add short circuit detection support
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel, devicetree, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
These devices support detecting and reporting short circuits across
the output stages. Add support for reporting these issue. Do this
by registering an interrupt if available and enabling this error
to trigger that interrupt in the device.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 42 ++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/tlv320aic31xx.h | 16 +++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 77ae8f36a943..fd3109366377 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -164,6 +164,7 @@ struct aic31xx_priv {
unsigned int sysclk;
u8 p_div;
int rate_div_line;
+ int irq;
};
struct aic31xx_rate_divs {
@@ -1258,6 +1259,27 @@ static const struct acpi_device_id aic31xx_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
#endif
+static irqreturn_t aic31xx_irq(int irq, void *data)
+{
+ struct aic31xx_priv *aic31xx = (struct aic31xx_priv *)data;
+ struct device *dev = aic31xx->dev;
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value);
+ if (ret) {
+ dev_err(dev, "Failed to read interrupt mask: %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (value & AIC31XX_HPLSCDETECT)
+ dev_err(dev, "Short circuit on Left output is detected\n");
+ if (value & AIC31XX_HPRSCDETECT)
+ dev_err(dev, "Short circuit on Right output is detected\n");
+
+ return IRQ_HANDLED;
+}
+
static int aic31xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1280,6 +1302,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
aic31xx->dev = &i2c->dev;
+ aic31xx->irq = i2c->irq;
aic31xx->codec_type = id->driver_data;
@@ -1318,6 +1341,25 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
+ if (aic31xx->irq > 0) {
+ regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1,
+ AIC31XX_GPIO1_FUNC_MASK,
+ AIC31XX_GPIO1_INT1 <<
+ AIC31XX_GPIO1_FUNC_SHIFT);
+
+ regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
+ AIC31XX_SC);
+
+ ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq,
+ NULL, aic31xx_irq,
+ IRQF_ONESHOT, "aic31xx-irq",
+ aic31xx);
+ if (ret) {
+ dev_err(aic31xx->dev, "Unable to request IRQ\n");
+ return ret;
+ }
+ }
+
if (aic31xx->codec_type & DAC31XX_BIT)
return snd_soc_register_codec(&i2c->dev,
&soc_codec_driver_aic31xx,
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index ab94e6a0c742..9dc85b6f6ad3 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -184,6 +184,22 @@ enum aic31xx_type {
#define AIC31XX_SC BIT(3)
#define AIC31XX_ENGINE BIT(2)
+/* AIC31XX_GPIO1 */
+#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2)
+#define AIC31XX_GPIO1_FUNC_SHIFT 2
+#define AIC31XX_GPIO1_DISABLED 0x00
+#define AIC31XX_GPIO1_INPUT 0x01
+#define AIC31XX_GPIO1_GPI 0x02
+#define AIC31XX_GPIO1_GPO 0x03
+#define AIC31XX_GPIO1_CLKOUT 0x04
+#define AIC31XX_GPIO1_INT1 0x05
+#define AIC31XX_GPIO1_INT2 0x06
+#define AIC31XX_GPIO1_ADC_WCLK 0x07
+#define AIC31XX_GPIO1_SBCLK 0x08
+#define AIC31XX_GPIO1_SWCLK 0x09
+#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10
+#define AIC31XX_GPIO1_SDOUT 0x11
+
/* AIC31XX_DACSETUP */
#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
--
2.15.0
^ permalink raw reply related
* [PATCH v2 15/19] ASoC: tlv320aic31xx: Reset registers during power up
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: devicetree, alsa-devel, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
Add a reset function that toggles the reset line if available or uses
the software reset command otherwise. Use this in power up to ensure the
registers are in a sane state. This is useful when the driver module
is reloaded, or after Kexec, warm-reboots, etc..
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index b51c2777e8d1..77ae8f36a943 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1031,6 +1031,24 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}
+static int aic31xx_reset(struct aic31xx_priv *aic31xx)
+{
+ int ret = 0;
+
+ if (aic31xx->gpio_reset) {
+ gpiod_set_value(aic31xx->gpio_reset, 1);
+ ndelay(10); /* At least 10ns */
+ gpiod_set_value(aic31xx->gpio_reset, 0);
+ } else {
+ ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1);
+ if (ret < 0)
+ dev_err(aic31xx->dev, "Could not reset device\n");
+ }
+ mdelay(1); /* At least 1ms */
+
+ return ret;
+}
+
static void aic31xx_clk_on(struct snd_soc_codec *codec)
{
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
@@ -1074,11 +1092,11 @@ static int aic31xx_power_on(struct snd_soc_codec *codec)
if (ret)
return ret;
- if (aic31xx->gpio_reset) {
- gpiod_set_value(aic31xx->gpio_reset, 0);
- udelay(100);
- }
regcache_cache_only(aic31xx->regmap, false);
+
+ /* Reset device registers for a consistent power-on like state */
+ aic31xx_reset(aic31xx);
+
ret = regcache_sync(aic31xx->regmap);
if (ret) {
dev_err(codec->dev,
--
2.15.0
^ permalink raw reply related
* [PATCH v2 14/19] ASoC: tlv320aic31xx: Remove regulator notification handling
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel, devicetree, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
A regulator being forcefully disabled is a catastrophic event that
should never happen to most devices, especially not sound CODECs.
In addition, our handler sets the reset line but never disables it
as no one is listening for an enable event, this is certainly broken
and was mosy likely just copied from other CODECs, lets just remove
this code.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 50 ----------------------------------------
1 file changed, 50 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index f7b1ec96d826..b51c2777e8d1 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -161,7 +161,6 @@ struct aic31xx_priv {
struct gpio_desc *gpio_reset;
int micbias_vg;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
- struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
unsigned int sysclk;
u8 p_div;
int rate_div_line;
@@ -1032,28 +1031,6 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}
-static int aic31xx_regulator_event(struct notifier_block *nb,
- unsigned long event, void *data)
-{
- struct aic31xx_disable_nb *disable_nb =
- container_of(nb, struct aic31xx_disable_nb, nb);
- struct aic31xx_priv *aic31xx = disable_nb->aic31xx;
-
- if (event & REGULATOR_EVENT_DISABLE) {
- /*
- * Put codec to reset and as at least one of the
- * supplies was disabled.
- */
- if (aic31xx->gpio_reset)
- gpiod_set_value(aic31xx->gpio_reset, 1);
-
- regcache_mark_dirty(aic31xx->regmap);
- dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
- }
-
- return 0;
-}
-
static void aic31xx_clk_on(struct snd_soc_codec *codec)
{
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
@@ -1167,20 +1144,6 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
aic31xx->codec = codec;
- for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
- aic31xx->disable_nb[i].nb.notifier_call =
- aic31xx_regulator_event;
- aic31xx->disable_nb[i].aic31xx = aic31xx;
- ret = regulator_register_notifier(aic31xx->supplies[i].consumer,
- &aic31xx->disable_nb[i].nb);
- if (ret) {
- dev_err(codec->dev,
- "Failed to request regulator notifier: %d\n",
- ret);
- return ret;
- }
- }
-
regcache_cache_only(aic31xx->regmap, true);
regcache_mark_dirty(aic31xx->regmap);
@@ -1195,21 +1158,8 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static int aic31xx_codec_remove(struct snd_soc_codec *codec)
-{
- struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
- regulator_unregister_notifier(aic31xx->supplies[i].consumer,
- &aic31xx->disable_nb[i].nb);
-
- return 0;
-}
-
static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
.probe = aic31xx_codec_probe,
- .remove = aic31xx_codec_remove,
.set_bias_level = aic31xx_set_bias_level,
.suspend_bias_off = true,
--
2.15.0
^ permalink raw reply related
* [PATCH v2 13/19] ASoC: tlv320aic31xx: Fix inverted BCLK handling
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: devicetree, alsa-devel, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
Currently BCLK inverting is only handled when the DAI format is
DSP, but the BCLK may be inverted in any supported mode. Without
this using this CODEC in any other mode than DSP with the BCLK
inverted leads to bad sampling timing and very poor audio quality.
Fixes: e00447fafbf7 ("ASoC: tlv320aic31xx: Add basic codec driver implementation")
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index b39db3eb06d0..f7b1ec96d826 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -939,6 +939,18 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
+ /* signal polarity */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface_reg2 |= AIC31XX_BCLKINV_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
+ return -EINVAL;
+ }
+
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -946,16 +958,12 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_DSP_A:
dsp_a_val = 0x1; /* fall through */
case SND_SOC_DAIFMT_DSP_B:
- /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- iface_reg2 |= AIC31XX_BCLKINV_MASK;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- break;
- default:
- return -EINVAL;
- }
+ /*
+ * NOTE: This CODEC samples on the falling edge of BCLK in
+ * DSP mode, this is inverted compared to what most DAIs
+ * expect, so we invert for this mode
+ */
+ iface_reg2 ^= AIC31XX_BCLKINV_MASK;
iface_reg1 |= (AIC31XX_DSP_MODE <<
AIC31XX_IFACE1_DATATYPE_SHIFT);
break;
--
2.15.0
^ permalink raw reply related
* [PATCH v2 12/19] ASoC: tlv320aic31xx: Add CODEC clock slave support
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: devicetree, alsa-devel, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
This CODEC supports being the WCLK and/or BCLK slave, add
support for this here.
Also make the alert into an error as alert is more urgent
than needed here and is rarely used.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 41e2d8077a62..b39db3eb06d0 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -926,8 +926,16 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_CBM_CFM:
iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ iface_reg1 |= AIC31XX_WCLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ iface_reg1 |= AIC31XX_BCLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
default:
- dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
+ dev_err(codec->dev, "Invalid DAI master/slave interface\n");
return -EINVAL;
}
--
2.15.0
^ permalink raw reply related
* [PATCH v2 11/19] ASoC: tlv320aic31xx: Check clock and divider before division
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel, devicetree, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
If our set_sysclk DAI callback has not been called yet p_div will be 0
and dividing by this will cause an error. Print an error message and
leave before this.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 252d99af6688..41e2d8077a62 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -755,11 +755,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
{
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int bclk_score = snd_soc_params_to_frame_size(params);
- int mclk_p = aic31xx->sysclk / aic31xx->p_div;
+ int mclk_p;
int bclk_n = 0;
int match = -1;
int i;
+ if (!aic31xx->sysclk || !aic31xx->p_div) {
+ dev_err(codec->dev, "Master clock not supplied\n");
+ return -EINVAL;
+ }
+ mclk_p = aic31xx->sysclk / aic31xx->p_div;
+
/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
snd_soc_update_bits(codec, AIC31XX_CLKMUX,
AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
--
2.15.0
^ permalink raw reply related
* [PATCH v2 10/19] ASoC: tlv320aic31xx: Add MICBIAS off setting
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel, devicetree, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
Leaving microphone bias off is a valid setting and even used in the DT
binding document example. Add this setting here and document the same.
Signed-off-by: Andrew F. Davis <afd@ti.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/sound/tlv320aic31xx.txt | 1 +
include/dt-bindings/sound/tlv320aic31xx-micbias.h | 1 +
sound/soc/codecs/tlv320aic31xx.c | 1 +
3 files changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
index 5b3c33bb99e5..411cc46a2c58 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
@@ -24,6 +24,7 @@ Optional properties:
- reset-gpios - GPIO specification for the active low RESET input.
- ai31xx-micbias-vg - MicBias Voltage setting
+ 0 or MICBIAS_OFF - MICBIAS output is powered off
1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
diff --git a/include/dt-bindings/sound/tlv320aic31xx-micbias.h b/include/dt-bindings/sound/tlv320aic31xx-micbias.h
index c6895a18a455..069484070fcf 100644
--- a/include/dt-bindings/sound/tlv320aic31xx-micbias.h
+++ b/include/dt-bindings/sound/tlv320aic31xx-micbias.h
@@ -2,6 +2,7 @@
#ifndef __DT_TLV320AIC31XX_MICBIAS_H
#define __DT_TLV320AIC31XX_MICBIAS_H
+#define MICBIAS_OFF 0
#define MICBIAS_2_0V 1
#define MICBIAS_2_5V 2
#define MICBIAS_AVDDV 3
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 0e00421d363b..252d99af6688 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1298,6 +1298,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg",
&micbias_value);
switch (micbias_value) {
+ case MICBIAS_OFF:
case MICBIAS_2_0V:
case MICBIAS_2_5V:
case MICBIAS_AVDDV:
--
2.15.0
^ permalink raw reply related
* [PATCH v2 09/19] ASoC: tlv320aic31xx: Remove platform data
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: devicetree, alsa-devel, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
Platform data is not used by anyone (at least in upstream) so
drop this data and switch to using fwnode(DT/ACPI) only.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 72 +++++++++++++---------------------------
sound/soc/codecs/tlv320aic31xx.h | 6 ----
2 files changed, 23 insertions(+), 55 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index ab03a19f6aaa..0e00421d363b 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -157,8 +157,9 @@ struct aic31xx_priv {
u8 i2c_regs_status;
struct device *dev;
struct regmap *regmap;
+ enum aic31xx_type codec_type;
struct gpio_desc *gpio_reset;
- struct aic31xx_pdata pdata;
+ int micbias_vg;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
unsigned int sysclk;
@@ -450,7 +451,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
/* change mic bias voltage to user defined */
snd_soc_update_bits(codec, AIC31XX_MICBIAS,
AIC31XX_MICBIAS_MASK,
- aic31xx->pdata.micbias_vg <<
+ aic31xx->micbias_vg <<
AIC31XX_MICBIAS_SHIFT);
dev_dbg(codec->dev, "%s: turned on\n", __func__);
break;
@@ -673,14 +674,14 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec)
int ret = 0;
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
- if (!(aic31xx->pdata.codec_type & DAC31XX_BIT))
+ if (!(aic31xx->codec_type & DAC31XX_BIT))
ret = snd_soc_add_codec_controls(
codec, aic31xx_snd_controls,
ARRAY_SIZE(aic31xx_snd_controls));
if (ret)
return ret;
- if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT)
+ if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT)
ret = snd_soc_add_codec_controls(
codec, aic311x_snd_controls,
ARRAY_SIZE(aic311x_snd_controls));
@@ -698,7 +699,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- if (aic31xx->pdata.codec_type & DAC31XX_BIT) {
+ if (aic31xx->codec_type & DAC31XX_BIT) {
ret = snd_soc_dapm_new_controls(
dapm, dac31xx_dapm_widgets,
ARRAY_SIZE(dac31xx_dapm_widgets));
@@ -722,7 +723,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
return ret;
}
- if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
+ if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
ret = snd_soc_dapm_new_controls(
dapm, aic311x_dapm_widgets,
ARRAY_SIZE(aic311x_dapm_widgets));
@@ -1257,42 +1258,6 @@ static const struct of_device_id tlv320aic31xx_of_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
-
-static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
-{
- struct device_node *np = aic31xx->dev->of_node;
- unsigned int value = MICBIAS_2_0V;
- int ret;
-
- of_property_read_u32(np, "ai31xx-micbias-vg", &value);
- switch (value) {
- case MICBIAS_2_0V:
- case MICBIAS_2_5V:
- case MICBIAS_AVDDV:
- aic31xx->pdata.micbias_vg = value;
- break;
- default:
- dev_err(aic31xx->dev,
- "Bad ai31xx-micbias-vg value %d DT\n",
- value);
- aic31xx->pdata.micbias_vg = MICBIAS_2_0V;
- }
-
- ret = of_get_named_gpio(np, "reset-gpios", 0);
- if (ret > 0) {
- aic31xx->pdata.gpio_reset = ret;
- } else {
- ret = of_get_named_gpio(np, "gpio-reset", 0);
- if (ret > 0) {
- dev_warn(aic31xx->dev, "Using deprecated property \"gpio-reset\", please update your DT");
- aic31xx->pdata.gpio_reset = ret;
- }
- }
-}
-#else /* CONFIG_OF */
-static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
-{
-}
#endif /* CONFIG_OF */
#ifdef CONFIG_ACPI
@@ -1307,6 +1272,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct aic31xx_priv *aic31xx;
+ unsigned int micbias_value = MICBIAS_2_0V;
int i, ret;
dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
@@ -1325,15 +1291,23 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
}
aic31xx->dev = &i2c->dev;
- aic31xx->pdata.codec_type = id->driver_data;
+ aic31xx->codec_type = id->driver_data;
dev_set_drvdata(aic31xx->dev, aic31xx);
- if (dev_get_platdata(aic31xx->dev))
- memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev),
- sizeof(aic31xx->pdata));
- else if (aic31xx->dev->of_node)
- aic31xx_pdata_from_of(aic31xx);
+ fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg",
+ &micbias_value);
+ switch (micbias_value) {
+ case MICBIAS_2_0V:
+ case MICBIAS_2_5V:
+ case MICBIAS_AVDDV:
+ aic31xx->micbias_vg = micbias_value;
+ break;
+ default:
+ dev_err(aic31xx->dev, "Bad ai31xx-micbias-vg value %d in DT\n",
+ micbias_value);
+ aic31xx->micbias_vg = MICBIAS_2_0V;
+ }
aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset",
GPIOD_OUT_LOW);
@@ -1353,7 +1327,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
- if (aic31xx->pdata.codec_type & DAC31XX_BIT)
+ if (aic31xx->codec_type & DAC31XX_BIT)
return snd_soc_register_codec(&i2c->dev,
&soc_codec_driver_aic31xx,
dac31xx_dai_driver,
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 15ac7cba86fe..ab94e6a0c742 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -29,12 +29,6 @@ enum aic31xx_type {
DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT,
};
-struct aic31xx_pdata {
- enum aic31xx_type codec_type;
- unsigned int gpio_reset;
- int micbias_vg;
-};
-
#define AIC31XX_REG(page, reg) ((page * 128) + reg)
#define AIC31XX_PAGECTL AIC31XX_REG(0, 0) /* Page Control Register */
--
2.15.0
^ permalink raw reply related
* [PATCH v2 08/19] ASoC: tlv320aic31xx: Switch GPIO handling to use gpiod_* API
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd-l0cyMroinI0@public.gmane.org>
Move to using newer gpiod_* GPIO handling functions. This simplifies
the code and eases dropping platform data in the next patch. Also
remember GPIO are active low, so set "1" to reset.
Signed-off-by: Andrew F. Davis <afd-l0cyMroinI0@public.gmane.org>
---
sound/soc/codecs/tlv320aic31xx.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index c84febd991a0..ab03a19f6aaa 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -157,6 +157,7 @@ struct aic31xx_priv {
u8 i2c_regs_status;
struct device *dev;
struct regmap *regmap;
+ struct gpio_desc *gpio_reset;
struct aic31xx_pdata pdata;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
@@ -1020,8 +1021,8 @@ static int aic31xx_regulator_event(struct notifier_block *nb,
* Put codec to reset and as at least one of the
* supplies was disabled.
*/
- if (gpio_is_valid(aic31xx->pdata.gpio_reset))
- gpio_set_value(aic31xx->pdata.gpio_reset, 0);
+ if (aic31xx->gpio_reset)
+ gpiod_set_value(aic31xx->gpio_reset, 1);
regcache_mark_dirty(aic31xx->regmap);
dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
@@ -1073,8 +1074,8 @@ static int aic31xx_power_on(struct snd_soc_codec *codec)
if (ret)
return ret;
- if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
- gpio_set_value(aic31xx->pdata.gpio_reset, 1);
+ if (aic31xx->gpio_reset) {
+ gpiod_set_value(aic31xx->gpio_reset, 0);
udelay(100);
}
regcache_cache_only(aic31xx->regmap, false);
@@ -1334,15 +1335,11 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
else if (aic31xx->dev->of_node)
aic31xx_pdata_from_of(aic31xx);
- if (aic31xx->pdata.gpio_reset) {
- ret = devm_gpio_request_one(aic31xx->dev,
- aic31xx->pdata.gpio_reset,
- GPIOF_OUT_INIT_HIGH,
- "aic31xx-reset-pin");
- if (ret < 0) {
- dev_err(aic31xx->dev, "not able to acquire gpio\n");
- return ret;
- }
+ aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(aic31xx->gpio_reset)) {
+ dev_err(aic31xx->dev, "not able to acquire gpio\n");
+ return PTR_ERR(aic31xx->gpio_reset);
}
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
--
2.15.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 07/19] ASoC: tlv320aic31xx: Merge init function into probe
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: devicetree, alsa-devel, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
The function aic31xx_device_init() is only called from probe and
does nothing that logically shouldn't be in probe, remove this
unneeded function call and move its code into probe where it was called.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.c | 55 ++++++++++++++++------------------------
1 file changed, 22 insertions(+), 33 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 07c014501e5e..c84febd991a0 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1302,9 +1302,29 @@ static const struct acpi_device_id aic31xx_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
#endif
-static int aic31xx_device_init(struct aic31xx_priv *aic31xx)
+static int aic31xx_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- int ret, i;
+ struct aic31xx_priv *aic31xx;
+ int i, ret;
+
+ dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
+ id->name, (int)id->driver_data);
+
+ aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
+ if (!aic31xx)
+ return -ENOMEM;
+
+ aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap);
+ if (IS_ERR(aic31xx->regmap)) {
+ ret = PTR_ERR(aic31xx->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+ aic31xx->dev = &i2c->dev;
+
+ aic31xx->pdata.codec_type = id->driver_data;
dev_set_drvdata(aic31xx->dev, aic31xx);
@@ -1336,37 +1356,6 @@ static int aic31xx_device_init(struct aic31xx_priv *aic31xx)
return ret;
}
- return 0;
-}
-
-static int aic31xx_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct aic31xx_priv *aic31xx;
- int ret;
-
- dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
- id->name, (int) id->driver_data);
-
- aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
- if (!aic31xx)
- return -ENOMEM;
-
- aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap);
- if (IS_ERR(aic31xx->regmap)) {
- ret = PTR_ERR(aic31xx->regmap);
- dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
- ret);
- return ret;
- }
- aic31xx->dev = &i2c->dev;
-
- aic31xx->pdata.codec_type = id->driver_data;
-
- ret = aic31xx_device_init(aic31xx);
- if (ret)
- return ret;
-
if (aic31xx->pdata.codec_type & DAC31XX_BIT)
return snd_soc_register_codec(&i2c->dev,
&soc_codec_driver_aic31xx,
--
2.15.0
^ permalink raw reply related
* [PATCH v2 06/19] ASoC: tlv320aic31xx: Reformat header file using GENMASK and BIT macros
From: Andrew F. Davis @ 2017-11-29 21:32 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren
Cc: devicetree, alsa-devel, linux-kernel, Andrew F . Davis
In-Reply-To: <20171129213300.20021-1-afd@ti.com>
We also move the comments describing the registers to after the register
definition to remove non-uniform vertical white-space, this makes
cross-referencing with the datasheet much easier.
Signed-off-by: Andrew F. Davis <afd@ti.com>
---
sound/soc/codecs/tlv320aic31xx.h | 460 +++++++++++++++++----------------------
1 file changed, 203 insertions(+), 257 deletions(-)
rewrite sound/soc/codecs/tlv320aic31xx.h (80%)
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
dissimilarity index 80%
index 6efea0485392..15ac7cba86fe 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -1,257 +1,203 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ALSA SoC TLV320AIC31xx CODEC Driver Definitions
- *
- * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
- */
-
-#ifndef _TLV320AIC31XX_H
-#define _TLV320AIC31XX_H
-
-#define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000
-
-#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
- | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \
- | SNDRV_PCM_FMTBIT_S32_LE)
-
-
-#define AIC31XX_STEREO_CLASS_D_BIT 0x1
-#define AIC31XX_MINIDSP_BIT 0x2
-#define DAC31XX_BIT 0x4
-
-enum aic31xx_type {
- AIC3100 = 0,
- AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
- AIC3120 = AIC31XX_MINIDSP_BIT,
- AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),
- DAC3100 = DAC31XX_BIT,
- DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT,
-};
-
-struct aic31xx_pdata {
- enum aic31xx_type codec_type;
- unsigned int gpio_reset;
- int micbias_vg;
-};
-
-#define AIC31XX_REG(page, reg) ((page * 128) + reg)
-
-/* Page Control Register */
-#define AIC31XX_PAGECTL AIC31XX_REG(0, 0)
-
-/* Page 0 Registers */
-/* Software reset register */
-#define AIC31XX_RESET AIC31XX_REG(0, 1)
-/* OT FLAG register */
-#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3)
-/* Clock clock Gen muxing, Multiplexers*/
-#define AIC31XX_CLKMUX AIC31XX_REG(0, 4)
-/* PLL P and R-VAL register */
-#define AIC31XX_PLLPR AIC31XX_REG(0, 5)
-/* PLL J-VAL register */
-#define AIC31XX_PLLJ AIC31XX_REG(0, 6)
-/* PLL D-VAL MSB register */
-#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7)
-/* PLL D-VAL LSB register */
-#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8)
-/* DAC NDAC_VAL register*/
-#define AIC31XX_NDAC AIC31XX_REG(0, 11)
-/* DAC MDAC_VAL register */
-#define AIC31XX_MDAC AIC31XX_REG(0, 12)
-/* DAC OSR setting register 1, MSB value */
-#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13)
-/* DAC OSR setting register 2, LSB value */
-#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14)
-#define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16)
-/* Clock setting register 8, PLL */
-#define AIC31XX_NADC AIC31XX_REG(0, 18)
-/* Clock setting register 9, PLL */
-#define AIC31XX_MADC AIC31XX_REG(0, 19)
-/* ADC Oversampling (AOSR) Register */
-#define AIC31XX_AOSR AIC31XX_REG(0, 20)
-/* Clock setting register 9, Multiplexers */
-#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25)
-/* Clock setting register 10, CLOCKOUT M divider value */
-#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26)
-/* Audio Interface Setting Register 1 */
-#define AIC31XX_IFACE1 AIC31XX_REG(0, 27)
-/* Audio Data Slot Offset Programming */
-#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28)
-/* Audio Interface Setting Register 2 */
-#define AIC31XX_IFACE2 AIC31XX_REG(0, 29)
-/* Clock setting register 11, BCLK N Divider */
-#define AIC31XX_BCLKN AIC31XX_REG(0, 30)
-/* Audio Interface Setting Register 3, Secondary Audio Interface */
-#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31)
-/* Audio Interface Setting Register 4 */
-#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32)
-/* Audio Interface Setting Register 5 */
-#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33)
-/* I2C Bus Condition */
-#define AIC31XX_I2C AIC31XX_REG(0, 34)
-/* ADC FLAG */
-#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36)
-/* DAC Flag Registers */
-#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37)
-#define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38)
-/* Sticky Interrupt flag (overflow) */
-#define AIC31XX_OFFLAG AIC31XX_REG(0, 39)
-/* Sticy DAC Interrupt flags */
-#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44)
-/* Sticy ADC Interrupt flags */
-#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45)
-/* DAC Interrupt flags 2 */
-#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46)
-/* ADC Interrupt flags 2 */
-#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47)
-/* INT1 interrupt control */
-#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48)
-/* INT2 interrupt control */
-#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49)
-/* GPIO1 control */
-#define AIC31XX_GPIO1 AIC31XX_REG(0, 51)
-
-#define AIC31XX_DACPRB AIC31XX_REG(0, 60)
-/* ADC Instruction Set Register */
-#define AIC31XX_ADCPRB AIC31XX_REG(0, 61)
-/* DAC channel setup register */
-#define AIC31XX_DACSETUP AIC31XX_REG(0, 63)
-/* DAC Mute and volume control register */
-#define AIC31XX_DACMUTE AIC31XX_REG(0, 64)
-/* Left DAC channel digital volume control */
-#define AIC31XX_LDACVOL AIC31XX_REG(0, 65)
-/* Right DAC channel digital volume control */
-#define AIC31XX_RDACVOL AIC31XX_REG(0, 66)
-/* Headset detection */
-#define AIC31XX_HSDETECT AIC31XX_REG(0, 67)
-/* ADC Digital Mic */
-#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81)
-/* ADC Digital Volume Control Fine Adjust */
-#define AIC31XX_ADCFGA AIC31XX_REG(0, 82)
-/* ADC Digital Volume Control Coarse Adjust */
-#define AIC31XX_ADCVOL AIC31XX_REG(0, 83)
-
-
-/* Page 1 Registers */
-/* Headphone drivers */
-#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31)
-/* Class-D Speakear Amplifier */
-#define AIC31XX_SPKAMP AIC31XX_REG(1, 32)
-/* HP Output Drivers POP Removal Settings */
-#define AIC31XX_HPPOP AIC31XX_REG(1, 33)
-/* Output Driver PGA Ramp-Down Period Control */
-#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34)
-/* DAC_L and DAC_R Output Mixer Routing */
-#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35)
-/* Left Analog Vol to HPL */
-#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36)
-/* Right Analog Vol to HPR */
-#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37)
-/* Left Analog Vol to SPL */
-#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38)
-/* Right Analog Vol to SPR */
-#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39)
-/* HPL Driver */
-#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40)
-/* HPR Driver */
-#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41)
-/* SPL Driver */
-#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42)
-/* SPR Driver */
-#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43)
-/* HP Driver Control */
-#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44)
-/* MIC Bias Control */
-#define AIC31XX_MICBIAS AIC31XX_REG(1, 46)
-/* MIC PGA*/
-#define AIC31XX_MICPGA AIC31XX_REG(1, 47)
-/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
-#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48)
-/* ADC Input Selection for M-Terminal */
-#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49)
-/* Input CM Settings */
-#define AIC31XX_MICPGACM AIC31XX_REG(1, 50)
-
-/* Bits, masks and shifts */
-
-/* AIC31XX_CLKMUX */
-#define AIC31XX_PLL_CLKIN_MASK 0x0c
-#define AIC31XX_PLL_CLKIN_SHIFT 2
-#define AIC31XX_PLL_CLKIN_MCLK 0
-#define AIC31XX_CODEC_CLKIN_MASK 0x03
-#define AIC31XX_CODEC_CLKIN_SHIFT 0
-#define AIC31XX_CODEC_CLKIN_PLL 3
-#define AIC31XX_CODEC_CLKIN_BCLK 1
-
-/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC,
- AIC31XX_BCLKN */
-#define AIC31XX_PLL_MASK 0x7f
-#define AIC31XX_PM_MASK 0x80
-
-/* AIC31XX_IFACE1 */
-#define AIC31XX_WORD_LEN_16BITS 0x00
-#define AIC31XX_WORD_LEN_20BITS 0x01
-#define AIC31XX_WORD_LEN_24BITS 0x02
-#define AIC31XX_WORD_LEN_32BITS 0x03
-#define AIC31XX_IFACE1_DATALEN_MASK 0x30
-#define AIC31XX_IFACE1_DATALEN_SHIFT (4)
-#define AIC31XX_IFACE1_DATATYPE_MASK 0xC0
-#define AIC31XX_IFACE1_DATATYPE_SHIFT (6)
-#define AIC31XX_I2S_MODE 0x00
-#define AIC31XX_DSP_MODE 0x01
-#define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02
-#define AIC31XX_LEFT_JUSTIFIED_MODE 0x03
-#define AIC31XX_IFACE1_MASTER_MASK 0x0C
-#define AIC31XX_BCLK_MASTER 0x08
-#define AIC31XX_WCLK_MASTER 0x04
-
-/* AIC31XX_DATA_OFFSET */
-#define AIC31XX_DATA_OFFSET_MASK 0xFF
-
-/* AIC31XX_IFACE2 */
-#define AIC31XX_BCLKINV_MASK 0x08
-#define AIC31XX_BDIVCLK_MASK 0x03
-#define AIC31XX_DAC2BCLK 0x00
-#define AIC31XX_DACMOD2BCLK 0x01
-#define AIC31XX_ADC2BCLK 0x02
-#define AIC31XX_ADCMOD2BCLK 0x03
-
-/* AIC31XX_ADCFLAG */
-#define AIC31XX_ADCPWRSTATUS_MASK 0x40
-
-/* AIC31XX_DACFLAG1 */
-#define AIC31XX_LDACPWRSTATUS_MASK 0x80
-#define AIC31XX_RDACPWRSTATUS_MASK 0x08
-#define AIC31XX_HPLDRVPWRSTATUS_MASK 0x20
-#define AIC31XX_HPRDRVPWRSTATUS_MASK 0x02
-#define AIC31XX_SPLDRVPWRSTATUS_MASK 0x10
-#define AIC31XX_SPRDRVPWRSTATUS_MASK 0x01
-
-/* AIC31XX_INTRDACFLAG */
-#define AIC31XX_HPSCDETECT_MASK 0x80
-#define AIC31XX_BUTTONPRESS_MASK 0x20
-#define AIC31XX_HSPLUG_MASK 0x10
-#define AIC31XX_LDRCTHRES_MASK 0x08
-#define AIC31XX_RDRCTHRES_MASK 0x04
-#define AIC31XX_DACSINT_MASK 0x02
-#define AIC31XX_DACAINT_MASK 0x01
-
-/* AIC31XX_INT1CTRL */
-#define AIC31XX_HSPLUGDET_MASK 0x80
-#define AIC31XX_BUTTONPRESSDET_MASK 0x40
-#define AIC31XX_DRCTHRES_MASK 0x20
-#define AIC31XX_AGCNOISE_MASK 0x10
-#define AIC31XX_OC_MASK 0x08
-#define AIC31XX_ENGINE_MASK 0x04
-
-/* AIC31XX_DACSETUP */
-#define AIC31XX_SOFTSTEP_MASK 0x03
-
-/* AIC31XX_DACMUTE */
-#define AIC31XX_DACMUTE_MASK 0x0C
-
-/* AIC31XX_MICBIAS */
-#define AIC31XX_MICBIAS_MASK 0x03
-#define AIC31XX_MICBIAS_SHIFT 0
-
-#endif /* _TLV320AIC31XX_H */
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC TLV320AIC31xx CODEC Driver Definitions
+ *
+ * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#ifndef _TLV320AIC31XX_H
+#define _TLV320AIC31XX_H
+
+#define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000
+
+#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AIC31XX_STEREO_CLASS_D_BIT BIT(1)
+#define AIC31XX_MINIDSP_BIT BIT(2)
+#define DAC31XX_BIT BIT(3)
+
+enum aic31xx_type {
+ AIC3100 = 0,
+ AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
+ AIC3120 = AIC31XX_MINIDSP_BIT,
+ AIC3111 = AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT,
+ DAC3100 = DAC31XX_BIT,
+ DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT,
+};
+
+struct aic31xx_pdata {
+ enum aic31xx_type codec_type;
+ unsigned int gpio_reset;
+ int micbias_vg;
+};
+
+#define AIC31XX_REG(page, reg) ((page * 128) + reg)
+
+#define AIC31XX_PAGECTL AIC31XX_REG(0, 0) /* Page Control Register */
+
+/* Page 0 Registers */
+#define AIC31XX_RESET AIC31XX_REG(0, 1) /* Software reset register */
+#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3) /* OT FLAG register */
+#define AIC31XX_CLKMUX AIC31XX_REG(0, 4) /* Clock clock Gen muxing, Multiplexers*/
+#define AIC31XX_PLLPR AIC31XX_REG(0, 5) /* PLL P and R-VAL register */
+#define AIC31XX_PLLJ AIC31XX_REG(0, 6) /* PLL J-VAL register */
+#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7) /* PLL D-VAL MSB register */
+#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8) /* PLL D-VAL LSB register */
+#define AIC31XX_NDAC AIC31XX_REG(0, 11) /* DAC NDAC_VAL register*/
+#define AIC31XX_MDAC AIC31XX_REG(0, 12) /* DAC MDAC_VAL register */
+#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13) /* DAC OSR setting register 1, MSB value */
+#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14) /* DAC OSR setting register 2, LSB value */
+#define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16)
+#define AIC31XX_NADC AIC31XX_REG(0, 18) /* Clock setting register 8, PLL */
+#define AIC31XX_MADC AIC31XX_REG(0, 19) /* Clock setting register 9, PLL */
+#define AIC31XX_AOSR AIC31XX_REG(0, 20) /* ADC Oversampling (AOSR) Register */
+#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25) /* Clock setting register 9, Multiplexers */
+#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26) /* Clock setting register 10, CLOCKOUT M divider value */
+#define AIC31XX_IFACE1 AIC31XX_REG(0, 27) /* Audio Interface Setting Register 1 */
+#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28) /* Audio Data Slot Offset Programming */
+#define AIC31XX_IFACE2 AIC31XX_REG(0, 29) /* Audio Interface Setting Register 2 */
+#define AIC31XX_BCLKN AIC31XX_REG(0, 30) /* Clock setting register 11, BCLK N Divider */
+#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31) /* Audio Interface Setting Register 3, Secondary Audio Interface */
+#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32) /* Audio Interface Setting Register 4 */
+#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33) /* Audio Interface Setting Register 5 */
+#define AIC31XX_I2C AIC31XX_REG(0, 34) /* I2C Bus Condition */
+#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36) /* ADC FLAG */
+#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37) /* DAC Flag Registers */
+#define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38)
+#define AIC31XX_OFFLAG AIC31XX_REG(0, 39) /* Sticky Interrupt flag (overflow) */
+#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44) /* Sticy DAC Interrupt flags */
+#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45) /* Sticy ADC Interrupt flags */
+#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46) /* DAC Interrupt flags 2 */
+#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47) /* ADC Interrupt flags 2 */
+#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48) /* INT1 interrupt control */
+#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49) /* INT2 interrupt control */
+#define AIC31XX_GPIO1 AIC31XX_REG(0, 51) /* GPIO1 control */
+#define AIC31XX_DACPRB AIC31XX_REG(0, 60)
+#define AIC31XX_ADCPRB AIC31XX_REG(0, 61) /* ADC Instruction Set Register */
+#define AIC31XX_DACSETUP AIC31XX_REG(0, 63) /* DAC channel setup register */
+#define AIC31XX_DACMUTE AIC31XX_REG(0, 64) /* DAC Mute and volume control register */
+#define AIC31XX_LDACVOL AIC31XX_REG(0, 65) /* Left DAC channel digital volume control */
+#define AIC31XX_RDACVOL AIC31XX_REG(0, 66) /* Right DAC channel digital volume control */
+#define AIC31XX_HSDETECT AIC31XX_REG(0, 67) /* Headset detection */
+#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81) /* ADC Digital Mic */
+#define AIC31XX_ADCFGA AIC31XX_REG(0, 82) /* ADC Digital Volume Control Fine Adjust */
+#define AIC31XX_ADCVOL AIC31XX_REG(0, 83) /* ADC Digital Volume Control Coarse Adjust */
+
+/* Page 1 Registers */
+#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31) /* Headphone drivers */
+#define AIC31XX_SPKAMP AIC31XX_REG(1, 32) /* Class-D Speakear Amplifier */
+#define AIC31XX_HPPOP AIC31XX_REG(1, 33) /* HP Output Drivers POP Removal Settings */
+#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34) /* Output Driver PGA Ramp-Down Period Control */
+#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35) /* DAC_L and DAC_R Output Mixer Routing */
+#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36) /* Left Analog Vol to HPL */
+#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37) /* Right Analog Vol to HPR */
+#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38) /* Left Analog Vol to SPL */
+#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39) /* Right Analog Vol to SPR */
+#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40) /* HPL Driver */
+#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41) /* HPR Driver */
+#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42) /* SPL Driver */
+#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43) /* SPR Driver */
+#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44) /* HP Driver Control */
+#define AIC31XX_MICBIAS AIC31XX_REG(1, 46) /* MIC Bias Control */
+#define AIC31XX_MICPGA AIC31XX_REG(1, 47) /* MIC PGA*/
+#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48) /* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
+#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49) /* ADC Input Selection for M-Terminal */
+#define AIC31XX_MICPGACM AIC31XX_REG(1, 50) /* Input CM Settings */
+
+/* Bits, masks, and shifts */
+
+/* AIC31XX_CLKMUX */
+#define AIC31XX_PLL_CLKIN_MASK GENMASK(3, 2)
+#define AIC31XX_PLL_CLKIN_SHIFT (2)
+#define AIC31XX_PLL_CLKIN_MCLK 0x00
+#define AIC31XX_PLL_CLKIN_BCKL 0x01
+#define AIC31XX_PLL_CLKIN_GPIO1 0x02
+#define AIC31XX_PLL_CLKIN_DIN 0x03
+#define AIC31XX_CODEC_CLKIN_MASK GENMASK(1, 0)
+#define AIC31XX_CODEC_CLKIN_SHIFT (0)
+#define AIC31XX_CODEC_CLKIN_MCLK 0x00
+#define AIC31XX_CODEC_CLKIN_BCLK 0x01
+#define AIC31XX_CODEC_CLKIN_GPIO1 0x02
+#define AIC31XX_CODEC_CLKIN_PLL 0x03
+
+/* AIC31XX_PLLPR */
+/* AIC31XX_NDAC */
+/* AIC31XX_MDAC */
+/* AIC31XX_NADC */
+/* AIC31XX_MADC */
+/* AIC31XX_BCLKN */
+#define AIC31XX_PLL_MASK GENMASK(6, 0)
+#define AIC31XX_PM_MASK BIT(7)
+
+/* AIC31XX_IFACE1 */
+#define AIC31XX_IFACE1_DATATYPE_MASK GENMASK(7, 6)
+#define AIC31XX_IFACE1_DATATYPE_SHIFT (6)
+#define AIC31XX_I2S_MODE 0x00
+#define AIC31XX_DSP_MODE 0x01
+#define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02
+#define AIC31XX_LEFT_JUSTIFIED_MODE 0x03
+#define AIC31XX_IFACE1_DATALEN_MASK GENMASK(5, 4)
+#define AIC31XX_IFACE1_DATALEN_SHIFT (4)
+#define AIC31XX_WORD_LEN_16BITS 0x00
+#define AIC31XX_WORD_LEN_20BITS 0x01
+#define AIC31XX_WORD_LEN_24BITS 0x02
+#define AIC31XX_WORD_LEN_32BITS 0x03
+#define AIC31XX_IFACE1_MASTER_MASK GENMASK(3, 2)
+#define AIC31XX_BCLK_MASTER BIT(2)
+#define AIC31XX_WCLK_MASTER BIT(3)
+
+/* AIC31XX_DATA_OFFSET */
+#define AIC31XX_DATA_OFFSET_MASK GENMASK(7, 0)
+
+/* AIC31XX_IFACE2 */
+#define AIC31XX_BCLKINV_MASK BIT(3)
+#define AIC31XX_BDIVCLK_MASK GENMASK(1, 0)
+#define AIC31XX_DAC2BCLK 0x00
+#define AIC31XX_DACMOD2BCLK 0x01
+#define AIC31XX_ADC2BCLK 0x02
+#define AIC31XX_ADCMOD2BCLK 0x03
+
+/* AIC31XX_ADCFLAG */
+#define AIC31XX_ADCPWRSTATUS_MASK BIT(6)
+
+/* AIC31XX_DACFLAG1 */
+#define AIC31XX_LDACPWRSTATUS_MASK BIT(7)
+#define AIC31XX_HPLDRVPWRSTATUS_MASK BIT(5)
+#define AIC31XX_SPLDRVPWRSTATUS_MASK BIT(4)
+#define AIC31XX_RDACPWRSTATUS_MASK BIT(3)
+#define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1)
+#define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
+
+/* AIC31XX_INTRDACFLAG */
+#define AIC31XX_HPLSCDETECT BIT(7)
+#define AIC31XX_HPRSCDETECT BIT(6)
+#define AIC31XX_BUTTONPRESS BIT(5)
+#define AIC31XX_HSPLUG BIT(4)
+#define AIC31XX_LDRCTHRES BIT(3)
+#define AIC31XX_RDRCTHRES BIT(2)
+#define AIC31XX_DACSINT BIT(1)
+#define AIC31XX_DACAINT BIT(0)
+
+/* AIC31XX_INT1CTRL */
+#define AIC31XX_HSPLUGDET BIT(7)
+#define AIC31XX_BUTTONPRESSDET BIT(6)
+#define AIC31XX_DRCTHRES BIT(5)
+#define AIC31XX_AGCNOISE BIT(4)
+#define AIC31XX_SC BIT(3)
+#define AIC31XX_ENGINE BIT(2)
+
+/* AIC31XX_DACSETUP */
+#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
+
+/* AIC31XX_DACMUTE */
+#define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
+
+/* AIC31XX_MICBIAS */
+#define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
+#define AIC31XX_MICBIAS_SHIFT 0
+
+#endif /* _TLV320AIC31XX_H */
--
2.15.0
^ permalink raw reply related
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