* Support for platform-esdhc-controller
@ 2010-09-06 10:34 Wolfram Sang
2010-09-06 10:34 ` [RFC 1/3] sdhci-pltfm: Add structure for host-specific data Wolfram Sang
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Wolfram Sang @ 2010-09-06 10:34 UTC (permalink / raw)
To: linux-arm-kernel
This is a patch series adding support for the esdhc-controller as a platform
device which can be found on e.g. mx35/51. It was tested using a mx35-based
Phytec pcm043. This is still a WIP! ADMA2 is not supported so far (mx35 just
has ADMA1 which is not supported by the core?) I will see if I can grab a
mx51-board later.
The following changes since commit 2bfc96a127bc1cc94d26bfaa40159966064f9c8c:
Linux 2.6.36-rc3 (2010-08-29 08:36:04 -0700)
are available in the git repository at:
git://git.pengutronix.de/git/wsa/linux-2.6.git pcm043-mmc
Wolfram Sang (3):
sdhci-pltfm: Add structure for host-specific data
mmc: add driver for imx35/51
pcm043: add resources for mmc
arch/arm/mach-mx3/mach-pcm043.c | 29 ++++++
drivers/mmc/host/Kconfig | 9 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-esdhc.c | 194 +++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/sdhci-pltfm.c | 10 ++-
drivers/mmc/host/sdhci-pltfm.h | 6 +
6 files changed, 247 insertions(+), 2 deletions(-)
create mode 100644 drivers/mmc/host/sdhci-esdhc.c
Regards,
Wolfram
^ permalink raw reply [flat|nested] 5+ messages in thread
* [RFC 1/3] sdhci-pltfm: Add structure for host-specific data
2010-09-06 10:34 Support for platform-esdhc-controller Wolfram Sang
@ 2010-09-06 10:34 ` Wolfram Sang
2010-09-06 10:34 ` [RFC 2/3] mmc: add driver for imx35/51 Wolfram Sang
2010-09-06 10:34 ` [RFC 3/3] pcm043: add resources for mmc Wolfram Sang
2 siblings, 0 replies; 5+ messages in thread
From: Wolfram Sang @ 2010-09-06 10:34 UTC (permalink / raw)
To: linux-arm-kernel
We need to carry some information per host, e.g. the clock.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/mmc/host/sdhci-pltfm.c | 7 +++++--
drivers/mmc/host/sdhci-pltfm.h | 5 +++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index e045e3c..bf522a1 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -55,6 +55,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct sdhci_host *host;
+ struct sdhci_pltfm_host *pltfm_host;
struct resource *iomem;
int ret;
@@ -72,15 +73,17 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
"experience problems.\n");
if (pdev->dev.parent)
- host = sdhci_alloc_host(pdev->dev.parent, 0);
+ host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
else
- host = sdhci_alloc_host(&pdev->dev, 0);
+ host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto err;
}
+ pltfm_host = sdhci_priv(host);
+
host->hw_name = "platform";
if (pdata && pdata->ops)
host->ops = pdata->ops;
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 900f329..c393289 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -13,6 +13,11 @@
#include <linux/sdhci-pltfm.h>
+struct sdhci_pltfm_host {
+ struct clk *clk;
+ u32 scratchpad; /* to handle quirks across io-accessor calls */
+};
+
extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC 2/3] mmc: add driver for imx35/51
2010-09-06 10:34 Support for platform-esdhc-controller Wolfram Sang
2010-09-06 10:34 ` [RFC 1/3] sdhci-pltfm: Add structure for host-specific data Wolfram Sang
@ 2010-09-06 10:34 ` Wolfram Sang
2010-09-06 10:34 ` [RFC 3/3] pcm043: add resources for mmc Wolfram Sang
2 siblings, 0 replies; 5+ messages in thread
From: Wolfram Sang @ 2010-09-06 10:34 UTC (permalink / raw)
To: linux-arm-kernel
WIP!
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/mmc/host/Kconfig | 9 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-esdhc.c | 194 ++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/sdhci-pltfm.c | 3 +
drivers/mmc/host/sdhci-pltfm.h | 1 +
5 files changed, 208 insertions(+), 0 deletions(-)
create mode 100644 drivers/mmc/host/sdhci-esdhc.c
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 68d1279..bba3aec 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -130,6 +130,15 @@ config MMC_SDHCI_CNS3XXX
If unsure, say N.
+config MMC_SDHCI_ESDHC
+ bool "SDHCI platform support for the Freescale eSDHC controller"
+ depends on MMC_SDHCI_PLTFM
+ select MMC_SDHCI_IO_ACCESSORS
+ help
+ This selects the Freescale eSDHC controller support.
+
+ If unsure, say N.
+
config MMC_SDHCI_S3C
tristate "SDHCI support on Samsung S3C SoC"
depends on MMC_SDHCI && PLAT_SAMSUNG
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 840bcb5..7bde748 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o
sdhci-platform-y := sdhci-pltfm.o
sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
+sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC) += sdhci-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
sdhci-of-y := sdhci-of-core.o
diff --git a/drivers/mmc/host/sdhci-esdhc.c b/drivers/mmc/host/sdhci-esdhc.c
new file mode 100644
index 0000000..dced0fd
--- /dev/null
+++ b/drivers/mmc/host/sdhci-esdhc.c
@@ -0,0 +1,194 @@
+/*
+ * Freescale eSDHC controller driver for the platform bus.
+ *
+ * derived from the OF-version. WIP!
+ *
+ * Copyright (c) 2010 Pengutronix e.K.
+ * Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mmc/host.h>
+#include <linux/clk.h>
+#include <linux/sdhci-pltfm.h>
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+
+/*
+ * Ops and quirks for the Freescale eSDHC controller.
+ */
+
+// FIXME: Share those with the OF-version
+#define ESDHC_SYSTEM_CONTROL 0x2c
+#define ESDHC_CLOCK_MASK 0x0000fff0
+#define ESDHC_PREDIV_SHIFT 8
+#define ESDHC_DIVIDER_SHIFT 4
+#define ESDHC_CLOCK_PEREN 0x00000004
+#define ESDHC_CLOCK_HCKEN 0x00000002
+#define ESDHC_CLOCK_IPGEN 0x00000001
+
+#define ESDHC_HOST_CONTROL_8BITBUS 0x04
+#define ESDHC_HOST_CONTROL_LE 0x20
+
+static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
+{
+ void __iomem *base = host->ioaddr + (reg & ~0x3);
+ u32 shift = (reg & 0x3) * 8;
+
+ writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
+{
+ if (unlikely(reg == SDHCI_HOST_VERSION))
+ reg ^= 2;
+
+ return readw(host->ioaddr + reg);
+}
+
+static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ switch (reg) {
+ case SDHCI_TRANSFER_MODE:
+ /*
+ * Postpone this write, we must do it together with a
+ * command write that is down below.
+ */
+ pltfm_host->scratchpad = val;
+ return;
+ case SDHCI_COMMAND:
+ writel(val << 16 | pltfm_host->scratchpad,
+ host->ioaddr + SDHCI_TRANSFER_MODE);
+ return;
+ case SDHCI_BLOCK_SIZE:
+ val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+ break;
+ }
+ esdhc_clrset_le(host, 0xffff, val, reg);
+}
+
+static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
+{
+ u32 new_val;
+
+ switch (reg) {
+ case SDHCI_POWER_CONTROL:
+ /* FSL put some DMA bits here */
+ //FIXME: Convert to regulator?
+ return;
+ case SDHCI_HOST_CONTROL:
+ /* FSL messed up here, so we can just keep those two */
+ new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+ /* ensure the endianess */
+ new_val |= ESDHC_HOST_CONTROL_LE;
+ /* DMA mode bits are shifted */
+ new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+
+ esdhc_clrset_le(host, 0xffff, new_val, reg);
+ return;
+ }
+ esdhc_clrset_le(host, 0xff, val, reg);
+}
+
+
+//FIXME: Share the next three with OF?
+static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ int pre_div = 2;
+ int div = 1;
+ u32 temp;
+
+ temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+ temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+ if (clock == 0)
+ goto out;
+
+ while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+ pre_div *= 2;
+
+ while (host->max_clk / pre_div / div > clock && div < 16)
+ div++;
+
+ dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+ clock, host->max_clk / pre_div / div);
+
+ pre_div >>= 1;
+ div--;
+
+ temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+ temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
+ (div << ESDHC_DIVIDER_SHIFT) | (pre_div << ESDHC_PREDIV_SHIFT));
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+ mdelay(100);
+out:
+ host->clock = clock;
+}
+
+static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ return clk_get_rate(pltfm_host->clk);
+}
+
+static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ return clk_get_rate(pltfm_host->clk) / 256 / 16;
+}
+
+static int esdhc_init(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct clk *clk;
+
+ clk = clk_get(NULL, "sdhc");
+ if (IS_ERR(clk)) {
+ dev_err(mmc_dev(host->mmc), "clk err\n");
+ return -ENODEV;
+ }
+ clk_enable(clk);
+ pltfm_host->clk = clk;
+
+ return 0;
+}
+
+static void esdhc_exit(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ clk_enable(pltfm_host->clk);
+ clk_put(pltfm_host->clk);
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+ .read_w = esdhc_readw_le,
+ .write_w = esdhc_writew_le,
+ .write_b = esdhc_writeb_le,
+ .set_clock = esdhc_set_clock,
+ .get_max_clock = esdhc_get_max_clock,
+ .get_min_clock = esdhc_get_min_clock,
+};
+
+struct sdhci_pltfm_data sdhci_esdhc_pdata = {
+ .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
+ SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+ SDHCI_QUIRK_NO_BUSY_IRQ |
+ SDHCI_QUIRK_NONSTANDARD_CLOCK |
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+ SDHCI_QUIRK_PIO_NEEDS_DELAY |
+ SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
+ SDHCI_QUIRK_NO_CARD_NO_RESET,
+ .ops = &sdhci_esdhc_ops,
+ .init = esdhc_init,
+ .exit = esdhc_exit,
+};
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index bf522a1..94be59f 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -164,6 +164,9 @@ static const struct platform_device_id sdhci_pltfm_ids[] = {
#ifdef CONFIG_MMC_SDHCI_CNS3XXX
{ "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
#endif
+#ifdef CONFIG_MMC_SDHCI_ESDHC
+ { "sdhci-esdhc", (kernel_ulong_t)&sdhci_esdhc_pdata },
+#endif
{ },
};
MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index c393289..4b1e1db 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -19,5 +19,6 @@ struct sdhci_pltfm_host {
};
extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
+extern struct sdhci_pltfm_data sdhci_esdhc_pdata;
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC 3/3] pcm043: add resources for mmc
2010-09-06 10:34 Support for platform-esdhc-controller Wolfram Sang
2010-09-06 10:34 ` [RFC 1/3] sdhci-pltfm: Add structure for host-specific data Wolfram Sang
2010-09-06 10:34 ` [RFC 2/3] mmc: add driver for imx35/51 Wolfram Sang
@ 2010-09-06 10:34 ` Wolfram Sang
2010-09-07 14:36 ` Uwe Kleine-König
2 siblings, 1 reply; 5+ messages in thread
From: Wolfram Sang @ 2010-09-06 10:34 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
arch/arm/mach-mx3/mach-pcm043.c | 29 +++++++++++++++++++++++++++++
1 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mx3/mach-pcm043.c b/arch/arm/mach-mx3/mach-pcm043.c
index 28886f0..44278d3 100644
--- a/arch/arm/mach-mx3/mach-pcm043.c
+++ b/arch/arm/mach-mx3/mach-pcm043.c
@@ -28,6 +28,7 @@
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
#include <linux/fsl_devices.h>
+#include <linux/mmc/host.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -139,10 +140,31 @@ static struct i2c_board_info pcm043_i2c_devices[] = {
};
#endif
+static struct resource sdhci_resources[] = {
+ {
+ .start = 0x53fb4000,
+ .end = 0x53fb4000 + 0xff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = MX35_INT_MMC_SDHC1,
+ .end = MX35_INT_MMC_SDHC1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhci_device = {
+ .name = "sdhci-esdhc",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sdhci_resources),
+ .resource = sdhci_resources,
+};
+
+
static struct platform_device *devices[] __initdata = {
&pcm043_flash,
&mxc_fec_device,
&imx_wdt_device0,
+ &sdhci_device,
};
static struct pad_desc pcm043_pads[] = {
@@ -217,6 +239,13 @@ static struct pad_desc pcm043_pads[] = {
/* CAN2 */
MX35_PAD_TX5_RX0__CAN2_TXCAN,
MX35_PAD_TX4_RX1__CAN2_RXCAN,
+ /* esdhc */
+ MX35_PAD_SD1_CMD__ESDHC1_CMD,
+ MX35_PAD_SD1_CLK__ESDHC1_CLK,
+ MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
+ MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
+ MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
+ MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
};
#define AC97_GPIO_TXFS (1 * 32 + 31)
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC 3/3] pcm043: add resources for mmc
2010-09-06 10:34 ` [RFC 3/3] pcm043: add resources for mmc Wolfram Sang
@ 2010-09-07 14:36 ` Uwe Kleine-König
0 siblings, 0 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2010-09-07 14:36 UTC (permalink / raw)
To: linux-arm-kernel
Hey Wolfram,
On Mon, Sep 06, 2010 at 12:34:25PM +0200, Wolfram Sang wrote:
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
> ---
> arch/arm/mach-mx3/mach-pcm043.c | 29 +++++++++++++++++++++++++++++
> 1 files changed, 29 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-mx3/mach-pcm043.c b/arch/arm/mach-mx3/mach-pcm043.c
> index 28886f0..44278d3 100644
> --- a/arch/arm/mach-mx3/mach-pcm043.c
> +++ b/arch/arm/mach-mx3/mach-pcm043.c
> @@ -28,6 +28,7 @@
> #include <linux/usb/otg.h>
> #include <linux/usb/ulpi.h>
> #include <linux/fsl_devices.h>
> +#include <linux/mmc/host.h>
>
> #include <asm/mach-types.h>
> #include <asm/mach/arch.h>
> @@ -139,10 +140,31 @@ static struct i2c_board_info pcm043_i2c_devices[] = {
> };
> #endif
>
> +static struct resource sdhci_resources[] = {
> + {
> + .start = 0x53fb4000,
> + .end = 0x53fb4000 + 0xff,
> + .flags = IORESOURCE_MEM,
> + }, {
> + .start = MX35_INT_MMC_SDHC1,
> + .end = MX35_INT_MMC_SDHC1,
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static struct platform_device sdhci_device = {
> + .name = "sdhci-esdhc",
> + .id = 0,
> + .num_resources = ARRAY_SIZE(sdhci_resources),
> + .resource = sdhci_resources,
> +};
> +
> +
> static struct platform_device *devices[] __initdata = {
> &pcm043_flash,
> &mxc_fec_device,
> &imx_wdt_device0,
> + &sdhci_device,
> };
>
> static struct pad_desc pcm043_pads[] = {
> @@ -217,6 +239,13 @@ static struct pad_desc pcm043_pads[] = {
> /* CAN2 */
> MX35_PAD_TX5_RX0__CAN2_TXCAN,
> MX35_PAD_TX4_RX1__CAN2_RXCAN,
> + /* esdhc */
> + MX35_PAD_SD1_CMD__ESDHC1_CMD,
> + MX35_PAD_SD1_CLK__ESDHC1_CLK,
> + MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
> + MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
> + MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
> + MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
> };
Can you please rework this to look like
http://news.gmane.org/find-root.php?group=gmane.linux.ports.arm.kernel&article=89213
(i.e. put a function in arch/arm/plat-mxc/devices/platform-sdhci-esdhc.c
that dynamically allocates the platform device.)
And then (maybe in a seperate patch) call this new function from the
init routine of the pcm043.
Thanks
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-09-07 14:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-09-06 10:34 Support for platform-esdhc-controller Wolfram Sang
2010-09-06 10:34 ` [RFC 1/3] sdhci-pltfm: Add structure for host-specific data Wolfram Sang
2010-09-06 10:34 ` [RFC 2/3] mmc: add driver for imx35/51 Wolfram Sang
2010-09-06 10:34 ` [RFC 3/3] pcm043: add resources for mmc Wolfram Sang
2010-09-07 14:36 ` Uwe Kleine-König
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).