From patchwork Fri Oct 12 13:47:36 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ujhelyi.m@gmail.com X-Patchwork-Id: 191132 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id D49942C0089 for ; Sat, 13 Oct 2012 00:48:20 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932808Ab2JLNsS (ORCPT ); Fri, 12 Oct 2012 09:48:18 -0400 Received: from mail-we0-f174.google.com ([74.125.82.174]:37202 "EHLO mail-we0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757848Ab2JLNsR (ORCPT ); Fri, 12 Oct 2012 09:48:17 -0400 Received: by mail-we0-f174.google.com with SMTP id t9so1683767wey.19 for ; Fri, 12 Oct 2012 06:48:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer; bh=q0q4am7QbrGkDEneWcy8SrerG36hbcBJ7o0vBratHMI=; b=J0DgXpxBn7t1JwV6eZghnlCgLHYu/6NPntEHZJceyDTK6t8A80xfGhBMZgpvnUv7+n V5niQe8/DqHS1Zh4dZWg0z1j1JbRsVExZtLDgXtO14qVxaxXl3LVFSwfBkc107dhKnhI 4CRiKwEDtTq+/Rd+yHqDX0nyj2MeI2xvxHDWiRxIqFwDlTCRqqdoe86rR+KXr18Hma53 2RugVTg0I5khnl4jhblyvxxktEGIK+cC0R4ba9Tf9W30cySiUaSDoVwFlyEFFEasiLQH QN2CnmnVHmhhs1fhRgM6jr3DlPQPu8CZQJYMePanifHUAOV5JSiuosY9E2W2pPVbrSNo lO8Q== Received: by 10.216.140.73 with SMTP id d51mr2623045wej.217.1350049696077; Fri, 12 Oct 2012 06:48:16 -0700 (PDT) Received: from matus-desktop.sueba ([81.89.61.168]) by mx.google.com with ESMTPS id j8sm3288711wiy.9.2012.10.12.06.48.14 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 12 Oct 2012 06:48:15 -0700 (PDT) From: ujhelyi.m@gmail.com To: netdev@vger.kernel.org Cc: davem@davemloft.net, daniel@zonque.org, rd@radekdostal.com, Matus Ujhelyi Subject: [PATCH] phy: add AT803x driver Date: Fri, 12 Oct 2012 15:47:36 +0200 Message-Id: <1350049656-22766-1-git-send-email-ujhelyi.m@gmail.com> X-Mailer: git-send-email 1.7.9.5 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Matus Ujhelyi This driver add support for wake over lan on AT803x phys. Signed-off-by: Matus Ujhelyi --- drivers/net/phy/Kconfig | 5 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/at803x.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 drivers/net/phy/at803x.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 3090dc6..e69d74e 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -15,6 +15,11 @@ if PHYLIB comment "MII PHY device drivers" +config AT803X_PHY + tristate "Drivers for Atheros PHYs" + ---help--- + Currently supports the AT8030 and AT8035 model + config AMD_PHY tristate "Drivers for the AMD PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 6d2dc6c..66720a5 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_STE10XP) += ste10Xp.o obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o +obj-$(CONFIG_AT803X_PHY) += at803x.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c new file mode 100644 index 0000000..45cbc10 --- /dev/null +++ b/drivers/net/phy/at803x.c @@ -0,0 +1,176 @@ +/* + * drivers/net/phy/at803x.c + * + * Driver for Atheros 803x PHY + * + * Author: Matus Ujhelyi + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#define AT803X_INTR_ENABLE 0x12 +#define AT803X_INTR_STATUS 0x13 +#define AT803X_WOL_ENABLE 0x01 +#define AT803X_DEVICE_ADDR 0x03 +#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C +#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B +#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A +#define AT803X_MMD_ACCESS_CONTROL 0x0D +#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E +#define AT803X_FUNC_DATA 0x4003 + +MODULE_DESCRIPTION("Atheros 803x PHY driver"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_LICENSE("GPL"); + +static void at803x_set_wol_mac_addr(struct phy_device *phydev) +{ + struct net_device *ndev = phydev->attached_dev; + const u8 *mac; + unsigned int i, offsets[] = { + AT803X_LOC_MAC_ADDR_32_47_OFFSET, + AT803X_LOC_MAC_ADDR_16_31_OFFSET, + AT803X_LOC_MAC_ADDR_0_15_OFFSET, + }; + + if (!ndev) + return; + + mac = (const u8 *) ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return; + + for (i = 0; i < 3; i++) { + phy_write(phydev, AT803X_MMD_ACCESS_CONTROL, + AT803X_DEVICE_ADDR); + phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA, + offsets[i]); + phy_write(phydev, AT803X_MMD_ACCESS_CONTROL, + AT803X_FUNC_DATA); + phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA, + mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); + } +} + +static int at803x_config_init(struct phy_device *phydev) +{ + int val; + u32 features; + int status; + + features = SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI | + SUPPORTED_FIBRE | SUPPORTED_BNC; + + val = phy_read(phydev, MII_BMSR); + if (val < 0) + return val; + + if (val & BMSR_ANEGCAPABLE) + features |= SUPPORTED_Autoneg; + if (val & BMSR_100FULL) + features |= SUPPORTED_100baseT_Full; + if (val & BMSR_100HALF) + features |= SUPPORTED_100baseT_Half; + if (val & BMSR_10FULL) + features |= SUPPORTED_10baseT_Full; + if (val & BMSR_10HALF) + features |= SUPPORTED_10baseT_Half; + + if (val & BMSR_ESTATEN) { + val = phy_read(phydev, MII_ESTATUS); + if (val < 0) + return val; + + if (val & ESTATUS_1000_TFULL) + features |= SUPPORTED_1000baseT_Full; + if (val & ESTATUS_1000_THALF) + features |= SUPPORTED_1000baseT_Half; + } + + phydev->supported = features; + phydev->advertising = features; + + /* enable WOL */ + at803x_set_wol_mac_addr(phydev); + status = phy_write(phydev, AT803X_INTR_ENABLE, AT803X_WOL_ENABLE); + status = phy_read(phydev, AT803X_INTR_STATUS); + + return 0; +} + +/* ATHEROS 8035 */ +static struct phy_driver at8035_driver = { + .phy_id = 0x004dd072, + .name = "Atheros 8035 ethernet", + .phy_id_mask = 0xffffffef, + .config_init = at803x_config_init, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .driver = { + .owner = THIS_MODULE, + }, +}; + +/* ATHEROS 8030 */ +static struct phy_driver at8030_driver = { + .phy_id = 0x004dd076, + .name = "Atheros 8030 ethernet", + .phy_id_mask = 0xffffffef, + .config_init = at803x_config_init, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .driver = { + .owner = THIS_MODULE, + }, +}; + +static int __init atheros_init(void) +{ + int ret; + + ret = phy_driver_register(&at8035_driver); + if (ret) + goto err1; + + ret = phy_driver_register(&at8030_driver); + if (ret) + goto err2; + + return 0; + +err2: + phy_driver_unregister(&at8035_driver); +err1: + return ret; +} + +static void __exit atheros_exit(void) +{ + phy_driver_unregister(&at8035_driver); + phy_driver_unregister(&at8030_driver); +} + +module_init(atheros_init); +module_exit(atheros_exit); + +static struct mdio_device_id __maybe_unused atheros_tbl[] = { + { 0x004dd076, 0xffffffef }, + { 0x004dd072, 0xffffffef }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, atheros_tbl);