diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:09:22 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:09:22 -0700 |
| commit | f4cdf7ca9a1fdcca413157df19753f388a5a224e (patch) | |
| tree | 60a31895b2446cd7fa27514e8c2843534a0de0da /drivers/net/phy/qsemi.c | |
| download | linux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.tar.gz linux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.zip | |
Merge tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-mediagrafted
Pull media updates from Mauro Carvalho Chehab:
- v4l2-core: added ISP statistics support and per-block validation
- v4l2-core: Allow unknown HDR10 white point and luminance
- New camera sensors: Sony IMX678 and IMX471m, Himax HM1092 IR sensor
- New codec: Milos: VPU v2.0 codec support
- isp driver: gained support for Dreamchip RPPX1 ISP framework
- vsp1 driver: gained support for RZ/T2H and RZ/N2H
- Novalake driver: gained CVS support for new NVL hardware
- dvb-core: fix feed leak on failed DMX_ADD_PID
- several driver fixes, cleanups and minor improvements
* tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits)
media: ipu-bridge: check all DMI entries when overriding sensor rotation
media: v4l2-async: avoid deleting unlinked ASC entry on link error
media: rzg2l-cru: Align bytesperline to hardware DMA stride requirement
media: intel/ipu6: fix async notifier cleanup leak on parse error
media: staging/ipu7: fix async notifier UAF on probe error path
media: amd: isp4: fix self-deadlock in isp4sd_pwron_and_init() error path
media: amd: isp4: release partial allocations in isp4if_alloc_fw_gpumem()
media: rcar-isp: Fix VSPX reference leaks
media: rcar-isp: Release ISPCORE resources
media: i2c: imx415: Release runtime PM reference on VBLANK error
media: i2c: imx415: Return test pattern write errors
media: renesas: vsp1: Declare index variables in for loop statement
media: renesas: vsp1: Make reset control optional to support platforms without a reset line
media: dt-bindings: media: renesas,vsp1: Document RZ/T2H and RZ/N2H SoCs
media: dt-bindings: media: renesas,fcp: Document RZ/T2H and RZ/N2H SoCs
media: nxp: imx8-isi: Add additional 32-bit RGB format support
media: nxp: imx8-isi: Add 16-bit raw Bayer format support
media: nxp: imx8-isi: Implement per-stream reference counting for multiplexed streams
media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks
media: nxp: imx8-isi: Correct color map between V4L2 and ISI
...
Diffstat (limited to 'drivers/net/phy/qsemi.c')
| -rw-r--r-- | drivers/net/phy/qsemi.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c new file mode 100644 index 000000000..7b70ba6ca --- /dev/null +++ b/drivers/net/phy/qsemi.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * drivers/net/phy/qsemi.c + * + * Driver for Quality Semiconductor PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + */ +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <linux/uaccess.h> + +/* ------------------------------------------------------------------------- */ +/* The Quality Semiconductor QS6612 is used on the RPX CLLF */ + +/* register definitions */ + +#define MII_QS6612_MCR 17 /* Mode Control Register */ +#define MII_QS6612_FTR 27 /* Factory Test Register */ +#define MII_QS6612_MCO 28 /* Misc. Control Register */ +#define MII_QS6612_ISR 29 /* Interrupt Source Register */ +#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ +#define MII_QS6612_IMR_INIT 0x003a +#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ + +#define QS6612_PCR_AN_COMPLETE 0x1000 +#define QS6612_PCR_RLBEN 0x0200 +#define QS6612_PCR_DCREN 0x0100 +#define QS6612_PCR_4B5BEN 0x0040 +#define QS6612_PCR_TX_ISOLATE 0x0020 +#define QS6612_PCR_MLT3_DIS 0x0002 +#define QS6612_PCR_SCRM_DESCRM 0x0001 + +MODULE_DESCRIPTION("Quality Semiconductor PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +/* Returns 0, unless there's a write error */ +static int qs6612_config_init(struct phy_device *phydev) +{ + /* The PHY powers up isolated on the RPX, + * so send a command to allow operation. + * XXX - My docs indicate this should be 0x0940 + * ...or something. The current value sets three + * reserved bits, bit 11, which specifies it should be + * set to one, bit 10, which specifies it should be set + * to 0, and bit 7, which doesn't specify. However, my + * docs are preliminary, and I will leave it like this + * until someone more knowledgable corrects me or it. + * -- Andy Fleming + */ + return phy_write(phydev, MII_QS6612_PCR, 0x0dc0); +} + +static int qs6612_ack_interrupt(struct phy_device *phydev) +{ + int err; + + /* The Interrupt Source register is not self-clearing, bits 4 and 5 are + * cleared when MII_BMSR is read and bits 1 and 3 are cleared when + * MII_EXPANSION is read + */ + err = phy_read(phydev, MII_QS6612_ISR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_BMSR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_EXPANSION); + + if (err < 0) + return err; + + return 0; +} + +static int qs6612_config_intr(struct phy_device *phydev) +{ + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* clear any interrupts before enabling them */ + err = qs6612_ack_interrupt(phydev); + if (err) + return err; + + err = phy_write(phydev, MII_QS6612_IMR, + MII_QS6612_IMR_INIT); + } else { + err = phy_write(phydev, MII_QS6612_IMR, 0); + if (err) + return err; + + /* clear any leftover interrupts */ + err = qs6612_ack_interrupt(phydev); + } + + return err; + +} + +static irqreturn_t qs6612_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, MII_QS6612_ISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & MII_QS6612_IMR_INIT)) + return IRQ_NONE; + + /* the interrupt source register is not self-clearing */ + qs6612_ack_interrupt(phydev); + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + +static struct phy_driver qs6612_driver[] = { { + .phy_id = 0x00181440, + .name = "QS6612", + .phy_id_mask = 0xfffffff0, + /* PHY_BASIC_FEATURES */ + .config_init = qs6612_config_init, + .config_intr = qs6612_config_intr, + .handle_interrupt = qs6612_handle_interrupt, +} }; + +module_phy_driver(qs6612_driver); + +static const struct mdio_device_id __maybe_unused qs6612_tbl[] = { + { 0x00181440, 0xfffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, qs6612_tbl); |
