From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> To: Bjorn Andersson <andersson@kernel.org>, Konrad Dybcio <konrad.dybcio@linaro.org>, Liam Girdwood <lgirdwood@gmail.com>, Mark Brown <broonie@kernel.org>, Rob Herring <robh+dt@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Conor Dooley <conor+dt@kernel.org>, Wesley Cheng <quic_wcheng@quicinc.com>, Bryan O'Donoghue <bryan.odonoghue@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Vinod Koul <vkoul@kernel.org>, Kishon Vijay Abraham I <kishon@kernel.org>, Guenter Roeck <linux@roeck-us.net>, Heikki Krogerus <heikki.krogerus@linux.intel.com>, Philipp Zabel <p.zabel@pengutronix.de> Cc: linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-usb@vger.kernel.org, linux-phy@lists.infradead.org Subject: [PATCH v2 12/15] phy: qcom: qmp-usbc: add support for the Type-C handling Date: Sat, 13 Jan 2024 22:55:55 +0200 [thread overview] Message-ID: <20240113-pmi632-typec-v2-12-182d9aa0a5b3@linaro.org> (raw) In-Reply-To: <20240113-pmi632-typec-v2-0-182d9aa0a5b3@linaro.org> The USB-C PHYs on the msm8998, QCM2290 and SM6115 platforms use special register to control which lanes of the Type-C port are used for the SuperSpeed USB connection. Mimic the qmp-combo driver and handle this register. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 97 +++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 52f1b3f7b81e..214cf4203de4 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -18,6 +18,8 @@ #include <linux/regulator/consumer.h> #include <linux/reset.h> #include <linux/slab.h> +#include <linux/usb/typec.h> +#include <linux/usb/typec_mux.h> #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" @@ -374,11 +376,17 @@ struct qmp_usbc { struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; + struct mutex phy_mutex; + enum phy_mode mode; + unsigned int usb_init_count; struct phy *phy; struct clk_fixed_rate pipe_clk_fixed; + + struct typec_switch_dev *sw; + enum typec_orientation orientation; }; static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) @@ -497,6 +505,7 @@ static int qmp_usbc_init(struct phy *phy) struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *pcs = qmp->pcs; + u32 val = 0; int ret; ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); @@ -523,6 +532,14 @@ static int qmp_usbc_init(struct phy *phy) qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); +#define SW_PORTSELECT_VAL BIT(0) +#define SW_PORTSELECT_MUX BIT(1) + /* Use software based port select and switch on typec orientation */ + val = SW_PORTSELECT_MUX; + if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) + val |= SW_PORTSELECT_VAL; + writel(val, qmp->pcs_misc); + return 0; err_assert_reset: @@ -620,23 +637,34 @@ static int qmp_usbc_power_off(struct phy *phy) static int qmp_usbc_enable(struct phy *phy) { + struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; + mutex_lock(&qmp->phy_mutex); + ret = qmp_usbc_init(phy); if (ret) - return ret; + goto out_unlock; ret = qmp_usbc_power_on(phy); - if (ret) + if (ret) { qmp_usbc_exit(phy); + goto out_unlock; + } + + qmp->usb_init_count++; +out_unlock: + mutex_unlock(&qmp->phy_mutex); return ret; } static int qmp_usbc_disable(struct phy *phy) { + struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; + qmp->usb_init_count--; ret = qmp_usbc_power_off(phy); if (ret) return ret; @@ -874,6 +902,61 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } +#if IS_ENABLED(CONFIG_TYPEC) +static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + struct qmp_usbc *qmp = typec_switch_get_drvdata(sw); + + if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE) + return 0; + + mutex_lock(&qmp->phy_mutex); + qmp->orientation = orientation; + + if (qmp->usb_init_count) { + qmp_usbc_power_off(qmp->phy); + qmp_usbc_exit(qmp->phy); + + qmp_usbc_init(qmp->phy); + qmp_usbc_power_on(qmp->phy); + } + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static void qmp_usbc_typec_unregister(void *data) +{ + struct qmp_usbc *qmp = data; + + typec_switch_unregister(qmp->sw); +} + +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + struct typec_switch_desc sw_desc = {}; + struct device *dev = qmp->dev; + + sw_desc.drvdata = qmp; + sw_desc.fwnode = dev->fwnode; + sw_desc.set = qmp_usbc_typec_switch_set; + qmp->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(qmp->sw)) { + dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw); + return PTR_ERR(qmp->sw); + } + + return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp); +} +#else +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + return 0; +} +#endif + static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np) { struct platform_device *pdev = to_platform_device(qmp->dev); @@ -994,16 +1077,24 @@ static int qmp_usbc_probe(struct platform_device *pdev) qmp->dev = dev; + qmp->orientation = TYPEC_ORIENTATION_NORMAL; + qmp->cfg = of_device_get_match_data(dev); if (!qmp->cfg) return -EINVAL; + mutex_init(&qmp->phy_mutex); + ret = qmp_usbc_vreg_init(qmp); if (ret) return ret; + ret = qmp_usbc_typec_switch_register(qmp); + if (ret) + return ret; + /* Check for legacy binding with child node. */ - np = of_get_next_available_child(dev->of_node, NULL); + np = of_get_child_by_name(dev->of_node, "phy"); if (np) { ret = qmp_usbc_parse_dt_legacy(qmp, np); } else { -- 2.39.2 -- linux-phy mailing list linux-phy@lists.infradead.org https://lists.infradead.org/mailman/listinfo/linux-phy
WARNING: multiple messages have this Message-ID (diff)
From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> To: Bjorn Andersson <andersson@kernel.org>, Konrad Dybcio <konrad.dybcio@linaro.org>, Liam Girdwood <lgirdwood@gmail.com>, Mark Brown <broonie@kernel.org>, Rob Herring <robh+dt@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Conor Dooley <conor+dt@kernel.org>, Wesley Cheng <quic_wcheng@quicinc.com>, Bryan O'Donoghue <bryan.odonoghue@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Vinod Koul <vkoul@kernel.org>, Kishon Vijay Abraham I <kishon@kernel.org>, Guenter Roeck <linux@roeck-us.net>, Heikki Krogerus <heikki.krogerus@linux.intel.com>, Philipp Zabel <p.zabel@pengutronix.de> Cc: linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-usb@vger.kernel.org, linux-phy@lists.infradead.org Subject: [PATCH v2 12/15] phy: qcom: qmp-usbc: add support for the Type-C handling Date: Sat, 13 Jan 2024 22:55:55 +0200 [thread overview] Message-ID: <20240113-pmi632-typec-v2-12-182d9aa0a5b3@linaro.org> (raw) In-Reply-To: <20240113-pmi632-typec-v2-0-182d9aa0a5b3@linaro.org> The USB-C PHYs on the msm8998, QCM2290 and SM6115 platforms use special register to control which lanes of the Type-C port are used for the SuperSpeed USB connection. Mimic the qmp-combo driver and handle this register. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 97 +++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 52f1b3f7b81e..214cf4203de4 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -18,6 +18,8 @@ #include <linux/regulator/consumer.h> #include <linux/reset.h> #include <linux/slab.h> +#include <linux/usb/typec.h> +#include <linux/usb/typec_mux.h> #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" @@ -374,11 +376,17 @@ struct qmp_usbc { struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; + struct mutex phy_mutex; + enum phy_mode mode; + unsigned int usb_init_count; struct phy *phy; struct clk_fixed_rate pipe_clk_fixed; + + struct typec_switch_dev *sw; + enum typec_orientation orientation; }; static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) @@ -497,6 +505,7 @@ static int qmp_usbc_init(struct phy *phy) struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *pcs = qmp->pcs; + u32 val = 0; int ret; ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); @@ -523,6 +532,14 @@ static int qmp_usbc_init(struct phy *phy) qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); +#define SW_PORTSELECT_VAL BIT(0) +#define SW_PORTSELECT_MUX BIT(1) + /* Use software based port select and switch on typec orientation */ + val = SW_PORTSELECT_MUX; + if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) + val |= SW_PORTSELECT_VAL; + writel(val, qmp->pcs_misc); + return 0; err_assert_reset: @@ -620,23 +637,34 @@ static int qmp_usbc_power_off(struct phy *phy) static int qmp_usbc_enable(struct phy *phy) { + struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; + mutex_lock(&qmp->phy_mutex); + ret = qmp_usbc_init(phy); if (ret) - return ret; + goto out_unlock; ret = qmp_usbc_power_on(phy); - if (ret) + if (ret) { qmp_usbc_exit(phy); + goto out_unlock; + } + + qmp->usb_init_count++; +out_unlock: + mutex_unlock(&qmp->phy_mutex); return ret; } static int qmp_usbc_disable(struct phy *phy) { + struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; + qmp->usb_init_count--; ret = qmp_usbc_power_off(phy); if (ret) return ret; @@ -874,6 +902,61 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } +#if IS_ENABLED(CONFIG_TYPEC) +static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + struct qmp_usbc *qmp = typec_switch_get_drvdata(sw); + + if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE) + return 0; + + mutex_lock(&qmp->phy_mutex); + qmp->orientation = orientation; + + if (qmp->usb_init_count) { + qmp_usbc_power_off(qmp->phy); + qmp_usbc_exit(qmp->phy); + + qmp_usbc_init(qmp->phy); + qmp_usbc_power_on(qmp->phy); + } + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static void qmp_usbc_typec_unregister(void *data) +{ + struct qmp_usbc *qmp = data; + + typec_switch_unregister(qmp->sw); +} + +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + struct typec_switch_desc sw_desc = {}; + struct device *dev = qmp->dev; + + sw_desc.drvdata = qmp; + sw_desc.fwnode = dev->fwnode; + sw_desc.set = qmp_usbc_typec_switch_set; + qmp->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(qmp->sw)) { + dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw); + return PTR_ERR(qmp->sw); + } + + return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp); +} +#else +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + return 0; +} +#endif + static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np) { struct platform_device *pdev = to_platform_device(qmp->dev); @@ -994,16 +1077,24 @@ static int qmp_usbc_probe(struct platform_device *pdev) qmp->dev = dev; + qmp->orientation = TYPEC_ORIENTATION_NORMAL; + qmp->cfg = of_device_get_match_data(dev); if (!qmp->cfg) return -EINVAL; + mutex_init(&qmp->phy_mutex); + ret = qmp_usbc_vreg_init(qmp); if (ret) return ret; + ret = qmp_usbc_typec_switch_register(qmp); + if (ret) + return ret; + /* Check for legacy binding with child node. */ - np = of_get_next_available_child(dev->of_node, NULL); + np = of_get_child_by_name(dev->of_node, "phy"); if (np) { ret = qmp_usbc_parse_dt_legacy(qmp, np); } else { -- 2.39.2
next prev parent reply other threads:[~2024-01-13 20:56 UTC|newest] Thread overview: 96+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-01-13 20:55 [PATCH v2 00/15] usb: typec: qcom-pmic-typec: enable support for PMI632 PMIC Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-13 20:55 ` [PATCH v2 01/15] dt-bindings: regulator: qcom,usb-vbus-regulator: add support for PMI632 Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-15 7:58 ` Krzysztof Kozlowski 2024-01-15 7:58 ` Krzysztof Kozlowski 2024-01-13 20:55 ` [PATCH v2 02/15] dt-bindings: usb: qcom,pmic-typec: add support for the PMI632 block Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-15 7:59 ` Krzysztof Kozlowski 2024-01-15 7:59 ` Krzysztof Kozlowski 2024-01-13 20:55 ` [PATCH v2 03/15] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: split from sc8280xp PHY schema Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-15 8:00 ` Krzysztof Kozlowski 2024-01-15 8:00 ` Krzysztof Kozlowski 2024-01-13 20:55 ` [PATCH v2 04/15] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: support USB-C data Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-15 9:15 ` Krzysztof Kozlowski 2024-01-15 9:15 ` Krzysztof Kozlowski 2024-01-15 9:47 ` Dmitry Baryshkov 2024-01-15 9:47 ` Dmitry Baryshkov 2024-01-15 10:21 ` Krzysztof Kozlowski 2024-01-15 10:21 ` Krzysztof Kozlowski 2024-01-13 20:55 ` [PATCH v2 05/15] usb: typec: tcpm: fix the PD disabled case Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-15 9:00 ` Alexander Stein 2024-01-15 9:00 ` Alexander Stein 2024-01-18 9:53 ` Heikki Krogerus 2024-01-18 9:53 ` Heikki Krogerus 2024-01-13 20:55 ` [PATCH v2 06/15] usb: typec: qcom-pmic-typec: fix arguments of qcom_pmic_typec_pdphy_set_roles Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-14 15:51 ` Bryan O'Donoghue 2024-01-14 15:51 ` Bryan O'Donoghue 2024-01-14 16:13 ` Bryan O'Donoghue 2024-01-14 16:13 ` Bryan O'Donoghue 2024-01-13 20:55 ` [PATCH v2 07/15] usb: typec: qcom-pmic-typec: allow different implementations for the PD PHY Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-13 20:55 ` [PATCH v2 08/15] usb: typec: qcom-pmic-typec: allow different implementations for the port backend Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-14 16:12 ` Bryan O'Donoghue 2024-01-14 16:12 ` Bryan O'Donoghue 2024-01-13 20:55 ` [PATCH v2 09/15] usb: typec: qcom-pmic-typec: add support for PMI632 PMIC Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-16 12:32 ` Konrad Dybcio 2024-01-16 12:32 ` Konrad Dybcio 2024-01-16 12:56 ` Dmitry Baryshkov 2024-01-16 12:56 ` Dmitry Baryshkov 2024-01-16 14:23 ` Heikki Krogerus 2024-01-16 14:23 ` Heikki Krogerus 2024-01-25 0:07 ` Dmitry Baryshkov 2024-01-25 0:07 ` Dmitry Baryshkov 2024-01-25 11:03 ` Heikki Krogerus 2024-01-25 11:03 ` Heikki Krogerus 2024-01-13 20:55 ` [PATCH v2 10/15] phy: qcom: qmp-usb: split USB-C PHY driver Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-16 12:33 ` Konrad Dybcio 2024-01-16 12:33 ` Konrad Dybcio 2024-01-13 20:55 ` [PATCH v2 11/15] phy: qcom: qmp-usb: drop dual-lane handling Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-17 0:07 ` Jeff Johnson 2024-01-17 0:07 ` Jeff Johnson 2024-01-13 20:55 ` Dmitry Baryshkov [this message] 2024-01-13 20:55 ` [PATCH v2 12/15] phy: qcom: qmp-usbc: add support for the Type-C handling Dmitry Baryshkov 2024-01-13 20:55 ` [PATCH v2 13/15] arm64: dts: qcom: pmi632: define USB-C related blocks Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-15 10:00 ` Konrad Dybcio 2024-01-15 10:00 ` Konrad Dybcio 2024-01-15 10:43 ` Dmitry Baryshkov 2024-01-15 10:43 ` Dmitry Baryshkov 2024-01-17 17:23 ` Bryan O'Donoghue 2024-01-17 17:23 ` Bryan O'Donoghue 2024-01-17 18:05 ` Dmitry Baryshkov 2024-01-17 18:05 ` Dmitry Baryshkov 2024-01-17 18:23 ` Bryan O'Donoghue 2024-01-17 18:23 ` Bryan O'Donoghue 2024-01-17 22:01 ` Bjorn Andersson 2024-01-17 22:01 ` Bjorn Andersson 2024-01-18 11:17 ` Konrad Dybcio 2024-01-18 11:17 ` Konrad Dybcio 2024-01-18 13:38 ` Dmitry Baryshkov 2024-01-18 13:38 ` Dmitry Baryshkov 2024-01-18 13:54 ` Konrad Dybcio 2024-01-18 13:54 ` Konrad Dybcio 2024-01-13 20:55 ` [PATCH v2 14/15] arm64: dts: qcom: sm6115: drop pipe clock selection Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-13 20:55 ` [PATCH v2 15/15] arm64: dts: qcom: qrb4210-rb2: enable USB-C port handling Dmitry Baryshkov 2024-01-13 20:55 ` Dmitry Baryshkov 2024-01-23 20:32 ` Luca Weiss 2024-01-23 20:32 ` Luca Weiss 2024-01-24 1:16 ` Dmitry Baryshkov 2024-01-24 1:16 ` Dmitry Baryshkov 2024-01-23 14:20 ` (subset) [PATCH v2 00/15] usb: typec: qcom-pmic-typec: enable support for PMI632 PMIC Vinod Koul 2024-01-23 14:20 ` Vinod Koul 2024-01-23 20:43 ` Luca Weiss 2024-01-23 20:43 ` Luca Weiss 2024-01-24 1:43 ` Dmitry Baryshkov 2024-01-24 1:43 ` Dmitry Baryshkov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20240113-pmi632-typec-v2-12-182d9aa0a5b3@linaro.org \ --to=dmitry.baryshkov@linaro.org \ --cc=andersson@kernel.org \ --cc=broonie@kernel.org \ --cc=bryan.odonoghue@linaro.org \ --cc=conor+dt@kernel.org \ --cc=devicetree@vger.kernel.org \ --cc=gregkh@linuxfoundation.org \ --cc=heikki.krogerus@linux.intel.com \ --cc=kishon@kernel.org \ --cc=konrad.dybcio@linaro.org \ --cc=krzysztof.kozlowski+dt@linaro.org \ --cc=lgirdwood@gmail.com \ --cc=linux-arm-msm@vger.kernel.org \ --cc=linux-phy@lists.infradead.org \ --cc=linux-usb@vger.kernel.org \ --cc=linux@roeck-us.net \ --cc=p.zabel@pengutronix.de \ --cc=quic_wcheng@quicinc.com \ --cc=robh+dt@kernel.org \ --cc=vkoul@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.