blob: 77e074f615e3be1f5017a90a7e21db8a95cf15fb [file] [log] [blame]
Sean Nelson3d135e62008-07-21 14:49:04 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008 Sean Nelson <snelson@nmt.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Sean Nelson3d135e62008-07-21 14:49:04 +000015 */
16
17#include <arch/io.h>
18#include <device/device.h>
19#include <device/pnp.h>
Nico Huber1c811282013-06-15 20:33:44 +020020#include <superio/conf_mode.h>
Sean Nelson3d135e62008-07-21 14:49:04 +000021#include <console/console.h>
22#include <string.h>
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -080023#include <lib.h>
Sean Nelson3d135e62008-07-21 14:49:04 +000024#include <pc80/mc146818rtc.h>
25#include <stdlib.h>
Edward O'Callaghandef00be2014-04-30 05:01:52 +100026#include <pc80/keyboard.h>
Edward O'Callaghan0403c8632014-04-30 17:17:03 +100027#include "chip.h"
Sean Nelson3d135e62008-07-21 14:49:04 +000028#include "w83697hf.h"
29
Florian Zumbiehl85392a82011-11-01 20:19:06 +010030static void hwmon_set_fan_divisor(unsigned int base, int num, unsigned int divisor) {
31 unsigned char enc, buf;
32
33 if (divisor) {
34 enc = log2(divisor);
35 if (1 << enc != divisor || enc > 7)
36 die("invalid fan divisor");
37 outb(0x4e, base + 5);
38 outb(0x00, base + 6);
39 outb(0x47, base + 5);
40 outb((inb(base + 6) & ~(0x30 << (num * 2))) | ((enc & 3) << (4 + num * 2)), base + 6);
41 outb(0x5d, base + 5);
42 buf = inb(base + 6);
43 /* the above inb() auto-increments the address pointer ... */
44 outb(0x5d, base + 5);
45 outb((buf & ~(0x20 << num)) | ((enc & 4) << (3 + num)), base + 6);
46 }
47}
48
Edward O'Callaghanf21bdc32014-10-21 07:43:41 +110049static void w83697hf_init(struct device *dev)
Sean Nelson3d135e62008-07-21 14:49:04 +000050{
Florian Zumbiehl85392a82011-11-01 20:19:06 +010051 struct resource *res0;
52 struct superio_winbond_w83697hf_config *cfg;
53
Sean Nelson3d135e62008-07-21 14:49:04 +000054 if (!dev->enabled)
55 return;
Florian Zumbiehl85392a82011-11-01 20:19:06 +010056
57 cfg = dev->chip_info;
58
59 switch (dev->path.pnp.device) {
60 case W83697HF_HWM:
61 if (cfg) {
62 res0 = find_resource(dev, PNP_IDX_IO0);
63 hwmon_set_fan_divisor(res0->base, 0, cfg->hwmon_fan1_divisor);
64 hwmon_set_fan_divisor(res0->base, 1, cfg->hwmon_fan2_divisor);
65 }
66 break;
67 }
Sean Nelson3d135e62008-07-21 14:49:04 +000068}
69
Sean Nelson3d135e62008-07-21 14:49:04 +000070static struct device_operations ops = {
71 .read_resources = pnp_read_resources,
Nico Huber0b2ee932013-06-15 19:58:35 +020072 .set_resources = pnp_set_resources,
73 .enable_resources = pnp_enable_resources,
74 .enable = pnp_alt_enable,
Sean Nelson3d135e62008-07-21 14:49:04 +000075 .init = w83697hf_init,
Nico Huber1c811282013-06-15 20:33:44 +020076 .ops_pnp_mode = &pnp_conf_mode_8787_aa,
Sean Nelson3d135e62008-07-21 14:49:04 +000077};
78
79static struct pnp_info pnp_dev_info[] = {
Uwe Hermanna69d9782010-11-15 19:35:14 +000080 { &ops, W83697HF_FDC, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, {0x07f8, 0}, },
81 { &ops, W83697HF_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, {0x07f8, 0}, },
82 { &ops, W83697HF_SP1, PNP_IO0 | PNP_IRQ0, {0x07f8, 0}, },
83 { &ops, W83697HF_SP2, PNP_IO0 | PNP_IRQ0, {0x07f8, 0}, },
84 { &ops, W83697HF_CIR, PNP_IO0 | PNP_IRQ0, {0x07f8, 0}, },
85 { &ops, W83697HF_GAME_GPIO1, PNP_IO0 | PNP_IO1 | PNP_IRQ0, {0x07ff, 0}, {0x07fe, 4}, },
Sean Nelson3d135e62008-07-21 14:49:04 +000086 { &ops, W83697HF_MIDI_GPIO5, },
87 { &ops, W83697HF_GPIO234, },
88 { &ops, W83697HF_ACPI, },
Uwe Hermanna69d9782010-11-15 19:35:14 +000089 { &ops, W83697HF_HWM, PNP_IO0 | PNP_IRQ0, {0x0ff8, 0}, },
Sean Nelson3d135e62008-07-21 14:49:04 +000090};
91
92static void enable_dev(struct device *dev)
93{
94 pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
95}
96
97struct chip_operations superio_winbond_w83697hf_ops = {
98 CHIP_NAME("Winbond W83697HF Super I/O")
99 .enable_dev = enable_dev,
100};