//! Fixed clock driver
use abi::error::Error;
use alloc::sync::Arc;
use device_api::{
    clock::{ClockController, ClockHandle, Hertz},
    device::{Device, DeviceInitContext},
};
use device_tree::{
    driver::{device_tree_driver, DeviceTreeClockController, Node, ProbeContext},
    DeviceTreePropertyRead, TProp,
};

struct FixedClock {
    name: &'static str,
    frequency: Hertz,
}

impl Device for FixedClock {
    unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
        Ok(())
    }

    fn display_name(&self) -> &str {
        self.name
    }
}

impl ClockController for FixedClock {
    fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
        debug_assert!(clock.is_none());
        Ok(self.frequency)
    }

    fn set_clock_rate(&self, _clock: Option<u32>, _rate: Hertz) -> Result<Hertz, Error> {
        Err(Error::InvalidOperation)
    }

    fn enable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
        // Assume always enabled
        Ok(())
    }

    fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
        Err(Error::InvalidOperation)
    }
}

impl DeviceTreeClockController for FixedClock {
    fn map_clock(
        self: Arc<Self>,
        _property: &TProp,
        _offset: usize,
    ) -> Option<(ClockHandle, usize)> {
        Some((
            ClockHandle {
                clock: None,
                parent: self,
            },
            0,
        ))
    }
}

device_tree_driver! {
    compatible: ["fixed-clock"],
    driver: {
        fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
            let name = node.name()?;
            let frequency = Hertz(node.property("clock-frequency")?.read_cell(0, 1)?);
            log::info!("fixed-clock {name}: {frequency}");
            let fixed = Arc::new(FixedClock { name, frequency });
            node.make_clock_controller(fixed.clone());
            Some(fixed)
        }
    }
}
