Lines Matching +full:lpc +full:- +full:snoop
1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Provides a simple driver to control the ASPEED LPC snoop interface which
7 * the host to an arbitrary LPC I/O port.
27 #define DEVICE_NAME "aspeed-lpc-snoop"
108 return container_of(file->private_data, in snoop_file_to_chan()
120 if (kfifo_is_empty(&chan->fifo)) { in snoop_file_read()
121 if (file->f_flags & O_NONBLOCK) in snoop_file_read()
122 return -EAGAIN; in snoop_file_read()
123 ret = wait_event_interruptible(chan->wq, in snoop_file_read()
124 !kfifo_is_empty(&chan->fifo)); in snoop_file_read()
125 if (ret == -ERESTARTSYS) in snoop_file_read()
126 return -EINTR; in snoop_file_read()
128 ret = kfifo_to_user(&chan->fifo, buffer, count, &copied); in snoop_file_read()
140 poll_wait(file, &chan->wq, pt); in snoop_file_poll()
141 return !kfifo_is_empty(&chan->fifo) ? EPOLLIN : 0; in snoop_file_poll()
154 if (!kfifo_initialized(&chan->fifo)) in put_fifo_with_discard()
156 if (kfifo_is_full(&chan->fifo)) in put_fifo_with_discard()
157 kfifo_skip(&chan->fifo); in put_fifo_with_discard()
158 kfifo_put(&chan->fifo, val); in put_fifo_with_discard()
159 wake_up_interruptible(&chan->wq); in put_fifo_with_discard()
167 if (regmap_read(lpc_snoop->regmap, HICR6, ®)) in aspeed_lpc_snoop_irq()
170 /* Check if one of the snoop channels is interrupting */ in aspeed_lpc_snoop_irq()
176 regmap_write(lpc_snoop->regmap, HICR6, reg); in aspeed_lpc_snoop_irq()
178 /* Read and save most recent snoop'ed data byte to FIFO */ in aspeed_lpc_snoop_irq()
179 regmap_read(lpc_snoop->regmap, SNPWDR, &data); in aspeed_lpc_snoop_irq()
184 put_fifo_with_discard(&lpc_snoop->chan[0], val); in aspeed_lpc_snoop_irq()
189 put_fifo_with_discard(&lpc_snoop->chan[1], val); in aspeed_lpc_snoop_irq()
198 struct device *dev = &pdev->dev; in aspeed_lpc_snoop_config_irq()
201 lpc_snoop->irq = platform_get_irq(pdev, 0); in aspeed_lpc_snoop_config_irq()
202 if (lpc_snoop->irq < 0) in aspeed_lpc_snoop_config_irq()
203 return -ENODEV; in aspeed_lpc_snoop_config_irq()
205 rc = devm_request_irq(dev, lpc_snoop->irq, in aspeed_lpc_snoop_config_irq()
209 dev_warn(dev, "Unable to request IRQ %d\n", lpc_snoop->irq); in aspeed_lpc_snoop_config_irq()
210 lpc_snoop->irq = 0; in aspeed_lpc_snoop_config_irq()
227 if (WARN_ON(channel->enabled)) in aspeed_lpc_enable_snoop()
228 return -EBUSY; in aspeed_lpc_enable_snoop()
230 init_waitqueue_head(&channel->wq); in aspeed_lpc_enable_snoop()
232 channel->cfg = cfg; in aspeed_lpc_enable_snoop()
233 channel->miscdev.minor = MISC_DYNAMIC_MINOR; in aspeed_lpc_enable_snoop()
234 channel->miscdev.fops = &snoop_fops; in aspeed_lpc_enable_snoop()
235 channel->miscdev.parent = dev; in aspeed_lpc_enable_snoop()
237 channel->miscdev.name = in aspeed_lpc_enable_snoop()
238 devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, cfg->index); in aspeed_lpc_enable_snoop()
239 if (!channel->miscdev.name) in aspeed_lpc_enable_snoop()
240 return -ENOMEM; in aspeed_lpc_enable_snoop()
242 rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL); in aspeed_lpc_enable_snoop()
246 rc = misc_register(&channel->miscdev); in aspeed_lpc_enable_snoop()
250 /* Enable LPC snoop channel at requested port */ in aspeed_lpc_enable_snoop()
251 regmap_set_bits(lpc_snoop->regmap, HICR5, cfg->hicr5_en); in aspeed_lpc_enable_snoop()
252 regmap_update_bits(lpc_snoop->regmap, SNPWADR, cfg->snpwadr_mask, in aspeed_lpc_enable_snoop()
253 lpc_port << cfg->snpwadr_shift); in aspeed_lpc_enable_snoop()
256 if (model_data && model_data->has_hicrb_ensnp) in aspeed_lpc_enable_snoop()
257 regmap_set_bits(lpc_snoop->regmap, HICRB, cfg->hicrb_en); in aspeed_lpc_enable_snoop()
259 channel->enabled = true; in aspeed_lpc_enable_snoop()
264 kfifo_free(&channel->fifo); in aspeed_lpc_enable_snoop()
272 if (!channel->enabled) in aspeed_lpc_disable_snoop()
276 regmap_clear_bits(lpc_snoop->regmap, HICR5, channel->cfg->hicr5_en); in aspeed_lpc_disable_snoop()
278 channel->enabled = false; in aspeed_lpc_disable_snoop()
280 misc_deregister(&channel->miscdev); in aspeed_lpc_disable_snoop()
281 kfifo_free(&channel->fifo); in aspeed_lpc_disable_snoop()
286 struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev); in aspeed_lpc_snoop_remove()
288 /* Disable both snoop channels */ in aspeed_lpc_snoop_remove()
289 aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[0]); in aspeed_lpc_snoop_remove()
290 aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[1]); in aspeed_lpc_snoop_remove()
301 dev = &pdev->dev; in aspeed_lpc_snoop_probe()
305 return -ENOMEM; in aspeed_lpc_snoop_probe()
307 np = pdev->dev.parent->of_node; in aspeed_lpc_snoop_probe()
308 if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && in aspeed_lpc_snoop_probe()
309 !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && in aspeed_lpc_snoop_probe()
310 !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { in aspeed_lpc_snoop_probe()
311 dev_err(dev, "unsupported LPC device binding\n"); in aspeed_lpc_snoop_probe()
312 return -ENODEV; in aspeed_lpc_snoop_probe()
315 lpc_snoop->regmap = syscon_node_to_regmap(np); in aspeed_lpc_snoop_probe()
316 if (IS_ERR(lpc_snoop->regmap)) in aspeed_lpc_snoop_probe()
317 return dev_err_probe(dev, PTR_ERR(lpc_snoop->regmap), "Couldn't get regmap\n"); in aspeed_lpc_snoop_probe()
319 dev_set_drvdata(&pdev->dev, lpc_snoop); in aspeed_lpc_snoop_probe()
321 lpc_snoop->clk = devm_clk_get_enabled(dev, NULL); in aspeed_lpc_snoop_probe()
322 if (IS_ERR(lpc_snoop->clk)) in aspeed_lpc_snoop_probe()
323 return dev_err_probe(dev, PTR_ERR(lpc_snoop->clk), "couldn't get clock"); in aspeed_lpc_snoop_probe()
329 static_assert(ARRAY_SIZE(channel_cfgs) == ARRAY_SIZE(lpc_snoop->chan), in aspeed_lpc_snoop_probe()
334 rc = of_property_read_u32_index(dev->of_node, "snoop-ports", idx, &port); in aspeed_lpc_snoop_probe()
338 rc = aspeed_lpc_enable_snoop(dev, lpc_snoop, &lpc_snoop->chan[idx], in aspeed_lpc_snoop_probe()
344 return idx == ASPEED_LPC_SNOOP_INDEX_0 ? -ENODEV : 0; in aspeed_lpc_snoop_probe()
361 { .compatible = "aspeed,ast2400-lpc-snoop",
363 { .compatible = "aspeed,ast2500-lpc-snoop",
365 { .compatible = "aspeed,ast2600-lpc-snoop",
384 MODULE_DESCRIPTION("Linux driver to control Aspeed LPC snoop functionality");